Skip to content

Commit

Permalink
Merge pull request #823 from ninoseki/urlscan-visibility
Browse files Browse the repository at this point in the history
feat: support urlscan.io submit/scan visibility
  • Loading branch information
ninoseki authored Jul 28, 2024
2 parents fbd5d45 + 3f19ce7 commit 541b172
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/command/runner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { err, errAsync, ok, okAsync, Result, ResultAsync } from "neverthrow";

import { URLScan } from "~/scanner";
import type { OptionsType } from "~/schemas";
import { Selector } from "~/selector";
import type {
Expand Down Expand Up @@ -139,6 +140,7 @@ export class CommandRunner {
break;
case "urlscan.io":
scanner.setAPIKey(this.options.urlscanAPIKey);
(scanner as URLScan).setVisibility(this.options.urlscanVisibility);
break;
case "VirusTotal":
scanner.setAPIKey(this.options.virusTotalAPIKey);
Expand Down
20 changes: 19 additions & 1 deletion src/options/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import "bulma/css/bulma.css";
import { onMounted, reactive, ref, watch } from "vue";
import { Scanners } from "../scanner";
import type { OptionsType, SearchableType } from "../schemas";
import { OptionsType, SearchableType } from "../schemas";
import { Searchers } from "../searcher";
import { getOptions, setOptions } from "../storage";
import type { ScannableType, Scanner, Searcher } from "../types";
Expand All @@ -31,6 +31,7 @@ const options = reactive<OptionsType>({
strict: true,
hybridAnalysisAPIKey: undefined,
urlscanAPIKey: undefined,
urlscanVisibility: "public",
virusTotalAPIKey: undefined,
disabledScannerNames: [],
disabledSearcherNames: [],
Expand Down Expand Up @@ -267,6 +268,23 @@ watch(options, async (newOptions) => {
/>
</div>
</div>
<div
class="field"
v-if="
isSelectedScanner(scanner) && scanner.name === 'urlscan.io'
"
>
<label class="label">Visibility</label>
<div class="control">
<div class="select">
<select v-model="options.urlscanVisibility">
<option>public</option>
<option>unlisted</option>
<option>private</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="box" id="searchers">
Expand Down
27 changes: 15 additions & 12 deletions src/scanner/urlscan.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { errAsync, ResultAsync } from "neverthrow";
import * as v from "valibot";

import type { urlscanVisibilityType } from "~/schemas";
import type { ScannableType } from "~/types";

import { Base } from "./base";
Expand All @@ -19,6 +20,7 @@ export class URLScan extends Base {
public name: string;
public supportedTypes: ScannableType[] = ["ip", "domain", "url"];
public apiKey?: string = undefined;
public visibility: urlscanVisibilityType = "public";

public constructor() {
super();
Expand All @@ -30,6 +32,10 @@ export class URLScan extends Base {
this.apiKey = apiKey;
}

public setVisibility(visibility: urlscanVisibilityType): void {
this.visibility = visibility;
}

scanByIP(ip: string) {
return this.scan(ip);
}
Expand All @@ -42,25 +48,22 @@ export class URLScan extends Base {
return this.scan(url);
}

private scan(query: string, isPublic = true) {
private scan(query: string) {
if (!this.apiKey) {
return errAsync("Please set your urlscan.io API key via the option.");
}

const body = JSON.stringify({
public: isPublic ? "on" : "off",
url: query,
});
const headers = {
"API-KEY": this.apiKey,
"content-type": "application/json",
};

const scan = async () => {
const res = await fetch(`${this.baseURL}/api/v1/scan/`, {
method: "POST",
headers,
body,
headers: {
"API-KEY": this.apiKey!,
"content-type": "application/json",
},
body: JSON.stringify({
visibility: this.visibility,
url: query,
}),
});

const data = await res.json();
Expand Down
9 changes: 9 additions & 0 deletions src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,21 @@ export const SelectorOptionsSchema = v.object({

export type SelectorOptionsType = v.InferOutput<typeof SelectorOptionsSchema>;

export const urlscanVisibility = v.union([
v.literal("public"),
v.literal("unlisted"),
v.literal("private"),
]);

export type urlscanVisibilityType = v.InferOutput<typeof urlscanVisibility>;

export const OtherOptionsSchema = v.object({
href: v.optional(v.boolean(), true),
disabledSearcherNames: v.optional(v.array(v.string()), []),
disabledScannerNames: v.optional(v.array(v.string()), []),
hybridAnalysisAPIKey: v.optional(v.string()),
urlscanAPIKey: v.optional(v.string()),
urlscanVisibility: v.optional(urlscanVisibility, "public"),
virusTotalAPIKey: v.optional(v.string()),
});

Expand Down
1 change: 1 addition & 0 deletions src/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export async function setOptions(options: OptionsType): Promise<void> {
disabledScannerNames: options.disabledScannerNames.map((n) => n),
hybridAnalysisAPIKey: options.hybridAnalysisAPIKey,
urlscanAPIKey: options.urlscanAPIKey,
urlscanVisibility: options.urlscanVisibility,
virusTotalAPIKey: options.virusTotalAPIKey,
},
});
Expand Down

0 comments on commit 541b172

Please sign in to comment.