• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ninoseki / mitaka / 13409117581

19 Feb 2025 09:15AM UTC coverage: 75.461% (+1.6%) from 73.847%
13409117581

push

github

web-flow
v2.4.0 (#865)

398 of 418 branches covered (95.22%)

Branch coverage included in aggregate %.

2182 of 3001 relevant lines covered (72.71%)

52.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/command/runner.ts
1
import { err, errAsync, ok, okAsync, Result, ResultAsync } from "neverthrow";
×
2

3
import { URLScan } from "~/scanner";
4
import type { CommandType, OptionsType } from "~/schemas";
5
import { Selector } from "~/selector";
×
6
import type {
7
  Scanner,
8
  ScannerMap,
9
  Searcher,
10
  SearcherMap,
11
  SelectorSlot,
12
} from "~/types";
13
import { isScanner, isSearcher } from "~/utils";
×
14

15
export class CommandRunner {
×
16
  public command: CommandType;
×
17
  protected options: OptionsType;
×
18

19
  public constructor(command: CommandType, options: OptionsType) {
×
20
    this.command = command;
×
21
    this.options = options;
×
22
  }
×
23

24
  private searcherMap: SearcherMap = {
×
25
    ip: (searcher: Searcher, query: string): Result<string, string> => {
×
26
      return searcher.searchByIP(query);
×
27
    },
×
28
    domain: (searcher: Searcher, query: string): Result<string, string> => {
×
29
      return searcher.searchByDomain(query);
×
30
    },
×
31
    url: (searcher: Searcher, query: string): Result<string, string> => {
×
32
      return searcher.searchByURL(query);
×
33
    },
×
34
    asn: (searcher: Searcher, query: string): Result<string, string> => {
×
35
      return searcher.searchByASN(query);
×
36
    },
×
37
    email: (searcher: Searcher, query: string): Result<string, string> => {
×
38
      return searcher.searchByEmail(query);
×
39
    },
×
40
    hash: (searcher: Searcher, query: string): Result<string, string> => {
×
41
      return searcher.searchByHash(query);
×
42
    },
×
43
    cve: (searcher: Searcher, query: string): Result<string, string> => {
×
44
      return searcher.searchByCVE(query);
×
45
    },
×
46
    btc: (searcher: Searcher, query: string): Result<string, string> => {
×
47
      return searcher.searchByBTC(query);
×
48
    },
×
49
    gaPubID: (searcher: Searcher, query: string): Result<string, string> => {
×
50
      return searcher.searchByGAPubID(query);
×
51
    },
×
52
    gaTrackID: (searcher: Searcher, query: string): Result<string, string> => {
×
53
      return searcher.searchByGATrackID(query);
×
54
    },
×
55
    eth: (searcher: Searcher, query: string): Result<string, string> => {
×
56
      return searcher.searchByETH(query);
×
57
    },
×
58
  };
×
59

60
  public search(): Result<string, string> {
×
61
    const getSlot = (): Result<SelectorSlot, string> => {
×
62
      const selector: Selector = new Selector(this.command.query, this.options);
×
63
      const slots: SelectorSlot[] = selector.getSearcherSlots();
×
64
      const slot = slots.find((s) => s.analyzer.name === this.command.name);
×
65
      if (!slot) {
×
66
        return err(`Slot for ${this.command.name} is missing`);
×
67
      }
×
68

69
      if (!isSearcher(slot.analyzer)) {
×
70
        return err(`${slot.analyzer.name} is not a searcher`);
×
71
      }
×
72

73
      return ok(slot);
×
74
    };
×
75

76
    const search = (slot: SelectorSlot) => {
×
77
      const searcher = slot.analyzer as Searcher;
×
78
      if (this.command.type in this.searcherMap) {
×
79
        const fn = this.searcherMap[this.command.type];
×
80
        return fn(searcher, slot.query);
×
81
      }
×
82
      return err("Something goes wrong");
×
83
    };
×
84

85
    return getSlot().andThen(search);
×
86
  }
×
87

88
  public searchAll(): Result<string, string>[] {
×
89
    const selector: Selector = new Selector(this.command.query, this.options);
×
90
    const slots: SelectorSlot[] = selector.getSearcherSlots();
×
91
    const slotsWithoutAll = slots.filter(
×
92
      (slot) => slot.analyzer.name !== "all",
×
93
    );
×
94
    return slotsWithoutAll.map((slot) => {
×
95
      const searcher = slot.analyzer as Searcher;
×
96
      if (this.command.type in this.searcherMap) {
×
97
        const fn = this.searcherMap[this.command.type];
×
98
        return fn(searcher, slot.query);
×
99
      }
×
100
      return err(`${this.command.type} is not supported`);
×
101
    });
×
102
  }
×
103

104
  private scannerMap: ScannerMap = {
×
105
    ip: (scanner: Scanner, query: string) => {
×
106
      return scanner.scanByIP(query);
×
107
    },
×
108
    domain: (scanner: Scanner, query: string) => {
×
109
      return scanner.scanByDomain(query);
×
110
    },
×
111
    url: (scanner: Scanner, query: string) => {
×
112
      return scanner.scanByURL(query);
×
113
    },
×
114
  };
×
115

116
  public scan(): ResultAsync<string, string> {
×
117
    const getSlot = (): ResultAsync<SelectorSlot, string> => {
×
118
      const selector: Selector = new Selector(this.command.query);
×
119
      const slots: SelectorSlot[] = selector.getScannerSlots();
×
120
      const slot = slots.find((s) => s.analyzer.name === this.command.name);
×
121

122
      if (!slot) {
×
123
        return errAsync(`Slot for ${this.command.name} is missing`);
×
124
      }
×
125

126
      if (!isScanner(slot.analyzer)) {
×
127
        return errAsync(`${slot.analyzer.name} is not a scanner`);
×
128
      }
×
129

130
      return okAsync(slot);
×
131
    };
×
132

133
    const scan = (slot: SelectorSlot): ResultAsync<string, string> => {
×
134
      const scanner = slot.analyzer as Scanner;
×
135

136
      switch (scanner.name) {
×
137
        case "HybridAnalysis":
×
138
          scanner.setAPIKey(this.options.hybridAnalysisAPIKey);
×
139
          break;
×
140
        case "urlscan.io":
×
141
          scanner.setAPIKey(this.options.urlscanAPIKey);
×
142
          (scanner as URLScan).setVisibility(this.options.urlscanVisibility);
×
143
          break;
×
144
        case "VirusTotal":
×
145
          scanner.setAPIKey(this.options.virusTotalAPIKey);
×
146
          break;
×
147
        default:
×
148
          break;
×
149
      }
×
150

151
      if (slot.type in this.scannerMap) {
×
152
        const fn = this.scannerMap[slot.type];
×
153
        return fn(scanner, slot.query);
×
154
      }
×
155

156
      return errAsync("Something goes wrong");
×
157
    };
×
158

159
    return getSlot().andThen(scan);
×
160
  }
×
161
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc