mihari 5.2.4 → 5.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/README.md +0 -10
- data/Rakefile +13 -1
- data/build_frontend.sh +1 -1
- data/frontend/.eslintrc.cjs +22 -0
- data/frontend/.gitignore +18 -12
- data/frontend/.prettierrc.json +8 -0
- data/frontend/env.d.ts +5 -0
- data/frontend/package-lock.json +5213 -9655
- data/frontend/package.json +38 -25
- data/frontend/src/App.vue +5 -5
- data/frontend/src/api-helper.ts +38 -40
- data/frontend/src/api.ts +40 -40
- data/frontend/src/components/ErrorMessage.vue +8 -8
- data/frontend/src/components/Loading.vue +4 -4
- data/frontend/src/components/Navbar.vue +10 -27
- data/frontend/src/components/Pagination.vue +35 -42
- data/frontend/src/components/alert/Alert.vue +22 -27
- data/frontend/src/components/alert/Alerts.vue +23 -25
- data/frontend/src/components/alert/AlertsWithPagination.vue +34 -34
- data/frontend/src/components/alert/AlertsWrapper.vue +43 -50
- data/frontend/src/components/alert/Form.vue +39 -40
- data/frontend/src/components/artifact/AS.vue +7 -7
- data/frontend/src/components/artifact/Artifact.vue +69 -86
- data/frontend/src/components/artifact/ArtifactTag.vue +21 -27
- data/frontend/src/components/artifact/ArtifactTags.vue +8 -8
- data/frontend/src/components/artifact/ArtifactWrapper.vue +22 -25
- data/frontend/src/components/artifact/CPEs.vue +6 -6
- data/frontend/src/components/artifact/DnsRecords.vue +9 -9
- data/frontend/src/components/artifact/Ports.vue +6 -6
- data/frontend/src/components/artifact/ReverseDnsNames.vue +7 -7
- data/frontend/src/components/artifact/Tags.vue +6 -6
- data/frontend/src/components/artifact/WhoisRecord.vue +7 -9
- data/frontend/src/components/config/Configs.vue +9 -12
- data/frontend/src/components/config/ConfigsWrapper.vue +14 -20
- data/frontend/src/components/link/Link.vue +7 -7
- data/frontend/src/components/link/Links.vue +16 -21
- data/frontend/src/components/rule/EditRule.vue +23 -23
- data/frontend/src/components/rule/EditRuleWrapper.vue +22 -28
- data/frontend/src/components/rule/Form.vue +28 -28
- data/frontend/src/components/rule/InputForm.vue +31 -25
- data/frontend/src/components/rule/NewRule.vue +19 -19
- data/frontend/src/components/rule/Rule.vue +28 -30
- data/frontend/src/components/rule/RuleWrapper.vue +24 -31
- data/frontend/src/components/rule/Rules.vue +26 -30
- data/frontend/src/components/rule/RulesWrapper.vue +40 -43
- data/frontend/src/components/rule/YAML.vue +19 -22
- data/frontend/src/components/tag/Tag.vue +24 -32
- data/frontend/src/components/tag/Tags.vue +11 -11
- data/frontend/src/countries.ts +23 -23
- data/frontend/src/index.ts +9 -12
- data/frontend/src/links/anyrun.ts +10 -10
- data/frontend/src/links/base.ts +3 -3
- data/frontend/src/links/censys.ts +10 -10
- data/frontend/src/links/crtsh.ts +10 -10
- data/frontend/src/links/dnslytics.ts +18 -18
- data/frontend/src/links/greynoise.ts +10 -10
- data/frontend/src/links/index.ts +15 -15
- data/frontend/src/links/intezer.ts +10 -10
- data/frontend/src/links/otx.ts +14 -14
- data/frontend/src/links/securitytrails.ts +15 -15
- data/frontend/src/links/shodan.ts +10 -10
- data/frontend/src/links/urlscan.ts +19 -19
- data/frontend/src/links/virustotal.ts +27 -27
- data/frontend/src/main.ts +38 -8
- data/frontend/src/router/index.ts +20 -20
- data/frontend/src/rule.ts +6 -6
- data/frontend/src/shims-vue.d.ts +2 -2
- data/frontend/src/types.ts +91 -91
- data/frontend/src/utils.ts +23 -29
- data/frontend/src/views/Alerts.vue +7 -7
- data/frontend/src/views/Artifact.vue +17 -17
- data/frontend/src/views/Configs.vue +7 -7
- data/frontend/src/views/EditRule.vue +17 -17
- data/frontend/src/views/NewRule.vue +10 -10
- data/frontend/src/views/Rule.vue +17 -17
- data/frontend/src/views/Rules.vue +7 -7
- data/frontend/tests/utils.spec.ts +9 -0
- data/frontend/tsconfig.app.json +21 -0
- data/frontend/tsconfig.json +10 -36
- data/frontend/tsconfig.node.json +13 -0
- data/frontend/tsconfig.vitest.json +12 -0
- data/frontend/vite.config.ts +24 -0
- data/frontend/vitest.config.ts +21 -0
- data/lefthook.yml +4 -2
- data/lib/mihari/analyzers/base.rb +48 -14
- data/lib/mihari/analyzers/binaryedge.rb +10 -15
- data/lib/mihari/analyzers/censys.rb +12 -15
- data/lib/mihari/analyzers/circl.rb +10 -10
- data/lib/mihari/analyzers/crtsh.rb +10 -6
- data/lib/mihari/analyzers/dnstwister.rb +6 -8
- data/lib/mihari/analyzers/feed.rb +21 -10
- data/lib/mihari/analyzers/greynoise.rb +10 -20
- data/lib/mihari/analyzers/onyphe.rb +9 -14
- data/lib/mihari/analyzers/otx.rb +8 -9
- data/lib/mihari/analyzers/passivetotal.rb +10 -10
- data/lib/mihari/analyzers/pulsedive.rb +21 -31
- data/lib/mihari/analyzers/securitytrails.rb +8 -6
- data/lib/mihari/analyzers/shodan.rb +8 -13
- data/lib/mihari/analyzers/urlscan.rb +15 -20
- data/lib/mihari/analyzers/virustotal.rb +16 -26
- data/lib/mihari/analyzers/virustotal_intelligence.rb +11 -17
- data/lib/mihari/analyzers/zoomeye.rb +12 -17
- data/lib/mihari/config.rb +133 -0
- data/lib/mihari/constants.rb +3 -0
- data/lib/mihari/emitters/slack.rb +13 -3
- data/lib/mihari/errors.rb +1 -1
- data/lib/mihari/http.rb +2 -3
- data/lib/mihari/schemas/analyzer.rb +2 -0
- data/lib/mihari/type_checker.rb +6 -6
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/endpoints/configs.rb +5 -1
- data/lib/mihari/web/public/assets/{index-eed1bcd8.css → index-b17c40c6.css} +1 -5
- data/lib/mihari/web/public/assets/index-f740e4f9.js +799 -0
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari/web/public/redoc-static.html +388 -2193
- data/lib/mihari.rb +9 -59
- data/mihari.gemspec +8 -8
- metadata +29 -117
- data/frontend/.browserslistrc +0 -3
- data/frontend/.eslintrc.js +0 -33
- data/frontend/babel.config.js +0 -3
- data/frontend/jest.config.js +0 -9
- data/frontend/tests/unit/utils.spec.ts +0 -7
- data/frontend/vite.config.js +0 -24
- data/lib/mihari/web/public/assets/fa-brands-400-20c4a58b.ttf +0 -0
- data/lib/mihari/web/public/assets/fa-brands-400-74833209.woff2 +0 -0
- data/lib/mihari/web/public/assets/fa-regular-400-528d022d.ttf +0 -0
- data/lib/mihari/web/public/assets/fa-regular-400-8e7e5ea1.woff2 +0 -0
- data/lib/mihari/web/public/assets/fa-solid-900-67a65763.ttf +0 -0
- data/lib/mihari/web/public/assets/fa-solid-900-7152a693.woff2 +0 -0
- data/lib/mihari/web/public/assets/fa-v4compatibility-0515a423.ttf +0 -0
- data/lib/mihari/web/public/assets/fa-v4compatibility-694a17c3.woff2 +0 -0
- data/lib/mihari/web/public/assets/index-ac4e5ffa.js +0 -50
data/frontend/src/utils.ts
CHANGED
@@ -1,60 +1,54 @@
|
|
1
|
-
import dayjs from "dayjs"
|
2
|
-
import relativeTime from "dayjs/plugin/relativeTime"
|
3
|
-
import timezone from "dayjs/plugin/timezone"
|
4
|
-
import utc from "dayjs/plugin/utc"
|
5
|
-
import { LocationQueryValue } from "vue-router"
|
1
|
+
import dayjs from "dayjs"
|
2
|
+
import relativeTime from "dayjs/plugin/relativeTime"
|
3
|
+
import timezone from "dayjs/plugin/timezone"
|
4
|
+
import utc from "dayjs/plugin/utc"
|
5
|
+
import type { LocationQueryValue } from "vue-router"
|
6
6
|
|
7
|
-
import { getCountryByCode } from "@/countries"
|
8
|
-
import { GCS, IPInfo } from "@/types"
|
7
|
+
import { getCountryByCode } from "@/countries"
|
8
|
+
import type { GCS, IPInfo } from "@/types"
|
9
9
|
|
10
|
-
dayjs.extend(relativeTime)
|
11
|
-
dayjs.extend(timezone)
|
12
|
-
dayjs.extend(utc)
|
10
|
+
dayjs.extend(relativeTime)
|
11
|
+
dayjs.extend(timezone)
|
12
|
+
dayjs.extend(utc)
|
13
13
|
|
14
14
|
export function getLocalDatetime(datetime: string): string {
|
15
|
-
return dayjs(datetime).local().format("YYYY-MM-DD HH:mm:ss")
|
15
|
+
return dayjs(datetime).local().format("YYYY-MM-DD HH:mm:ss")
|
16
16
|
}
|
17
17
|
|
18
18
|
export function getHumanizedRelativeTime(datetime: string): string {
|
19
|
-
return dayjs(datetime).local().fromNow()
|
19
|
+
return dayjs(datetime).local().fromNow()
|
20
20
|
}
|
21
21
|
|
22
22
|
export function getGCSByCountryCode(countryCode: string): GCS | undefined {
|
23
|
-
const country = getCountryByCode(countryCode)
|
23
|
+
const country = getCountryByCode(countryCode)
|
24
24
|
if (country !== undefined) {
|
25
|
-
return { lat: country.lat, long: country.long }
|
25
|
+
return { lat: country.lat, long: country.long }
|
26
26
|
}
|
27
27
|
}
|
28
28
|
|
29
29
|
export function getGCSByIPInfo(ipinfo: IPInfo): GCS | undefined {
|
30
30
|
if (ipinfo.loc !== undefined) {
|
31
|
-
const numbers = ipinfo.loc.split(",")
|
31
|
+
const numbers = ipinfo.loc.split(",")
|
32
32
|
if (numbers.length === 2) {
|
33
|
-
const lat = numbers[0]
|
34
|
-
const long = numbers[1]
|
33
|
+
const lat = numbers[0]
|
34
|
+
const long = numbers[1]
|
35
35
|
|
36
|
-
return { lat: parseFloat(lat), long: parseFloat(long) }
|
36
|
+
return { lat: parseFloat(lat), long: parseFloat(long) }
|
37
37
|
}
|
38
38
|
}
|
39
|
-
return getGCSByCountryCode(ipinfo.countryCode)
|
39
|
+
return getGCSByCountryCode(ipinfo.countryCode)
|
40
40
|
}
|
41
41
|
|
42
42
|
export function normalizeQueryParam(
|
43
|
-
param:
|
44
|
-
| undefined
|
45
|
-
| null
|
46
|
-
| string
|
47
|
-
| string[]
|
48
|
-
| LocationQueryValue
|
49
|
-
| LocationQueryValue[]
|
43
|
+
param: undefined | null | string | string[] | LocationQueryValue | LocationQueryValue[]
|
50
44
|
): string | undefined {
|
51
45
|
if (param === undefined || param === null) {
|
52
|
-
return undefined
|
46
|
+
return undefined
|
53
47
|
}
|
54
48
|
|
55
49
|
if (typeof param === "string") {
|
56
|
-
return param
|
50
|
+
return param
|
57
51
|
}
|
58
52
|
|
59
|
-
return param.toString()
|
53
|
+
return param.toString()
|
60
54
|
}
|
@@ -3,18 +3,18 @@
|
|
3
3
|
</template>
|
4
4
|
|
5
5
|
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent } from "vue"
|
6
|
+
import { useTitle } from "@vueuse/core"
|
7
|
+
import { defineComponent } from "vue"
|
8
8
|
|
9
|
-
import Alerts from "@/components/alert/AlertsWrapper.vue"
|
9
|
+
import Alerts from "@/components/alert/AlertsWrapper.vue"
|
10
10
|
|
11
11
|
export default defineComponent({
|
12
12
|
name: "AlertsView",
|
13
13
|
components: {
|
14
|
-
Alerts
|
14
|
+
Alerts
|
15
15
|
},
|
16
16
|
setup() {
|
17
|
-
useTitle("Alerts - Mihari")
|
18
|
-
}
|
19
|
-
})
|
17
|
+
useTitle("Alerts - Mihari")
|
18
|
+
}
|
19
|
+
})
|
20
20
|
</script>
|
@@ -3,42 +3,42 @@
|
|
3
3
|
</template>
|
4
4
|
|
5
5
|
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent, onMounted, ref, watch } from "vue"
|
6
|
+
import { useTitle } from "@vueuse/core"
|
7
|
+
import { defineComponent, onMounted, ref, watch } from "vue"
|
8
8
|
|
9
|
-
import Artifact from "@/components/artifact/ArtifactWrapper.vue"
|
9
|
+
import Artifact from "@/components/artifact/ArtifactWrapper.vue"
|
10
10
|
|
11
11
|
export default defineComponent({
|
12
12
|
name: "ArtifactView",
|
13
13
|
components: {
|
14
|
-
Artifact
|
14
|
+
Artifact
|
15
15
|
},
|
16
16
|
props: {
|
17
17
|
id: {
|
18
18
|
type: String,
|
19
|
-
required: true
|
20
|
-
}
|
19
|
+
required: true
|
20
|
+
}
|
21
21
|
},
|
22
22
|
setup(props) {
|
23
|
-
const artifactId = ref<string>(props.id)
|
23
|
+
const artifactId = ref<string>(props.id)
|
24
24
|
|
25
25
|
const updateTitle = () => {
|
26
|
-
useTitle(`Artifact:${artifactId.value} - Mihari`)
|
27
|
-
}
|
26
|
+
useTitle(`Artifact:${artifactId.value} - Mihari`)
|
27
|
+
}
|
28
28
|
|
29
29
|
onMounted(() => {
|
30
|
-
updateTitle()
|
31
|
-
})
|
30
|
+
updateTitle()
|
31
|
+
})
|
32
32
|
|
33
33
|
watch(
|
34
34
|
() => props.id,
|
35
35
|
() => {
|
36
|
-
artifactId.value = props.id
|
37
|
-
updateTitle()
|
36
|
+
artifactId.value = props.id
|
37
|
+
updateTitle()
|
38
38
|
}
|
39
|
-
)
|
39
|
+
)
|
40
40
|
|
41
|
-
return { artifactId }
|
42
|
-
}
|
43
|
-
})
|
41
|
+
return { artifactId }
|
42
|
+
}
|
43
|
+
})
|
44
44
|
</script>
|
@@ -3,18 +3,18 @@
|
|
3
3
|
</template>
|
4
4
|
|
5
5
|
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent } from "vue"
|
6
|
+
import { useTitle } from "@vueuse/core"
|
7
|
+
import { defineComponent } from "vue"
|
8
8
|
|
9
|
-
import Configs from "@/components/config/ConfigsWrapper.vue"
|
9
|
+
import Configs from "@/components/config/ConfigsWrapper.vue"
|
10
10
|
|
11
11
|
export default defineComponent({
|
12
12
|
name: "ConfigView",
|
13
13
|
components: {
|
14
|
-
Configs
|
14
|
+
Configs
|
15
15
|
},
|
16
16
|
setup() {
|
17
|
-
useTitle("Config - Mihari")
|
18
|
-
}
|
19
|
-
})
|
17
|
+
useTitle("Config - Mihari")
|
18
|
+
}
|
19
|
+
})
|
20
20
|
</script>
|
@@ -3,42 +3,42 @@
|
|
3
3
|
</template>
|
4
4
|
|
5
5
|
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent, onMounted, ref, watch } from "vue"
|
6
|
+
import { useTitle } from "@vueuse/core"
|
7
|
+
import { defineComponent, onMounted, ref, watch } from "vue"
|
8
8
|
|
9
|
-
import EditRule from "@/components/rule/EditRuleWrapper.vue"
|
9
|
+
import EditRule from "@/components/rule/EditRuleWrapper.vue"
|
10
10
|
|
11
11
|
export default defineComponent({
|
12
12
|
name: "EditRuleView",
|
13
13
|
components: {
|
14
|
-
EditRule
|
14
|
+
EditRule
|
15
15
|
},
|
16
16
|
props: {
|
17
17
|
id: {
|
18
18
|
type: String,
|
19
|
-
required: true
|
20
|
-
}
|
19
|
+
required: true
|
20
|
+
}
|
21
21
|
},
|
22
22
|
setup(props) {
|
23
|
-
const ruleId = ref<string>(props.id)
|
23
|
+
const ruleId = ref<string>(props.id)
|
24
24
|
|
25
25
|
const updateTitle = () => {
|
26
|
-
useTitle(`Edit rule:${ruleId.value} - Mihari`)
|
27
|
-
}
|
26
|
+
useTitle(`Edit rule:${ruleId.value} - Mihari`)
|
27
|
+
}
|
28
28
|
|
29
29
|
onMounted(() => {
|
30
|
-
updateTitle()
|
31
|
-
})
|
30
|
+
updateTitle()
|
31
|
+
})
|
32
32
|
|
33
33
|
watch(
|
34
34
|
() => props.id,
|
35
35
|
() => {
|
36
|
-
ruleId.value = props.id
|
37
|
-
updateTitle()
|
36
|
+
ruleId.value = props.id
|
37
|
+
updateTitle()
|
38
38
|
}
|
39
|
-
)
|
39
|
+
)
|
40
40
|
|
41
|
-
return { ruleId }
|
42
|
-
}
|
43
|
-
})
|
41
|
+
return { ruleId }
|
42
|
+
}
|
43
|
+
})
|
44
44
|
</script>
|
@@ -3,24 +3,24 @@
|
|
3
3
|
</template>
|
4
4
|
|
5
5
|
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent, onMounted } from "vue"
|
6
|
+
import { useTitle } from "@vueuse/core"
|
7
|
+
import { defineComponent, onMounted } from "vue"
|
8
8
|
|
9
|
-
import NewRule from "@/components/rule/NewRule.vue"
|
9
|
+
import NewRule from "@/components/rule/NewRule.vue"
|
10
10
|
|
11
11
|
export default defineComponent({
|
12
12
|
name: "NewRuleView",
|
13
13
|
components: {
|
14
|
-
NewRule
|
14
|
+
NewRule
|
15
15
|
},
|
16
16
|
setup() {
|
17
17
|
const updateTitle = () => {
|
18
|
-
useTitle(`New rule - Mihari`)
|
19
|
-
}
|
18
|
+
useTitle(`New rule - Mihari`)
|
19
|
+
}
|
20
20
|
|
21
21
|
onMounted(() => {
|
22
|
-
updateTitle()
|
23
|
-
})
|
24
|
-
}
|
25
|
-
})
|
22
|
+
updateTitle()
|
23
|
+
})
|
24
|
+
}
|
25
|
+
})
|
26
26
|
</script>
|
data/frontend/src/views/Rule.vue
CHANGED
@@ -3,42 +3,42 @@
|
|
3
3
|
</template>
|
4
4
|
|
5
5
|
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent, onMounted, ref, watch } from "vue"
|
6
|
+
import { useTitle } from "@vueuse/core"
|
7
|
+
import { defineComponent, onMounted, ref, watch } from "vue"
|
8
8
|
|
9
|
-
import Rule from "@/components/rule/RuleWrapper.vue"
|
9
|
+
import Rule from "@/components/rule/RuleWrapper.vue"
|
10
10
|
|
11
11
|
export default defineComponent({
|
12
12
|
name: "RuleView",
|
13
13
|
components: {
|
14
|
-
Rule
|
14
|
+
Rule
|
15
15
|
},
|
16
16
|
props: {
|
17
17
|
id: {
|
18
18
|
type: String,
|
19
|
-
required: true
|
20
|
-
}
|
19
|
+
required: true
|
20
|
+
}
|
21
21
|
},
|
22
22
|
setup(props) {
|
23
|
-
const ruleId = ref<string>(props.id)
|
23
|
+
const ruleId = ref<string>(props.id)
|
24
24
|
|
25
25
|
const updateTitle = () => {
|
26
|
-
useTitle(`Rule:${ruleId.value} - Mihari`)
|
27
|
-
}
|
26
|
+
useTitle(`Rule:${ruleId.value} - Mihari`)
|
27
|
+
}
|
28
28
|
|
29
29
|
onMounted(() => {
|
30
|
-
updateTitle()
|
31
|
-
})
|
30
|
+
updateTitle()
|
31
|
+
})
|
32
32
|
|
33
33
|
watch(
|
34
34
|
() => props.id,
|
35
35
|
() => {
|
36
|
-
ruleId.value = props.id
|
37
|
-
updateTitle()
|
36
|
+
ruleId.value = props.id
|
37
|
+
updateTitle()
|
38
38
|
}
|
39
|
-
)
|
39
|
+
)
|
40
40
|
|
41
|
-
return { ruleId }
|
42
|
-
}
|
43
|
-
})
|
41
|
+
return { ruleId }
|
42
|
+
}
|
43
|
+
})
|
44
44
|
</script>
|
@@ -3,18 +3,18 @@
|
|
3
3
|
</template>
|
4
4
|
|
5
5
|
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent } from "vue"
|
6
|
+
import { useTitle } from "@vueuse/core"
|
7
|
+
import { defineComponent } from "vue"
|
8
8
|
|
9
|
-
import Rules from "@/components/rule/RulesWrapper.vue"
|
9
|
+
import Rules from "@/components/rule/RulesWrapper.vue"
|
10
10
|
|
11
11
|
export default defineComponent({
|
12
12
|
name: "RulesView",
|
13
13
|
components: {
|
14
|
-
Rules
|
14
|
+
Rules
|
15
15
|
},
|
16
16
|
setup() {
|
17
|
-
useTitle("Rules - Mihari")
|
18
|
-
}
|
19
|
-
})
|
17
|
+
useTitle("Rules - Mihari")
|
18
|
+
}
|
19
|
+
})
|
20
20
|
</script>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
2
|
+
|
3
|
+
import { getHumanizedRelativeTime } from '@/utils'
|
4
|
+
|
5
|
+
describe('getHumanizedRelativeTime', () => {
|
6
|
+
it('returns a relative time in humanized format', () => {
|
7
|
+
expect(getHumanizedRelativeTime('1970-01-01 00:00:00')).toContain('years')
|
8
|
+
})
|
9
|
+
})
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
3
|
+
"include": [
|
4
|
+
"env.d.ts",
|
5
|
+
"src/**/*",
|
6
|
+
"src/**/*.vue",
|
7
|
+
"tests/**/*"
|
8
|
+
],
|
9
|
+
"exclude": [
|
10
|
+
"src/**/__tests__/*"
|
11
|
+
],
|
12
|
+
"compilerOptions": {
|
13
|
+
"composite": true,
|
14
|
+
"baseUrl": ".",
|
15
|
+
"paths": {
|
16
|
+
"@/*": [
|
17
|
+
"./src/*"
|
18
|
+
]
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
data/frontend/tsconfig.json
CHANGED
@@ -1,40 +1,14 @@
|
|
1
1
|
{
|
2
|
-
"
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
"jsx": "preserve",
|
7
|
-
"importHelpers": true,
|
8
|
-
"moduleResolution": "node",
|
9
|
-
"skipLibCheck": true,
|
10
|
-
"esModuleInterop": true,
|
11
|
-
"allowSyntheticDefaultImports": true,
|
12
|
-
"sourceMap": true,
|
13
|
-
"baseUrl": ".",
|
14
|
-
"types": [
|
15
|
-
"webpack-env",
|
16
|
-
"jest"
|
17
|
-
],
|
18
|
-
"paths": {
|
19
|
-
"@/*": [
|
20
|
-
"src/*"
|
21
|
-
]
|
2
|
+
"files": [],
|
3
|
+
"references": [
|
4
|
+
{
|
5
|
+
"path": "./tsconfig.node.json"
|
22
6
|
},
|
23
|
-
|
24
|
-
"
|
25
|
-
|
26
|
-
|
27
|
-
"
|
28
|
-
|
29
|
-
},
|
30
|
-
"include": [
|
31
|
-
"src/**/*.ts",
|
32
|
-
"src/**/*.tsx",
|
33
|
-
"src/**/*.vue",
|
34
|
-
"tests/**/*.ts",
|
35
|
-
"tests/**/*.tsx"
|
36
|
-
],
|
37
|
-
"exclude": [
|
38
|
-
"node_modules"
|
7
|
+
{
|
8
|
+
"path": "./tsconfig.app.json"
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"path": "./tsconfig.vitest.json"
|
12
|
+
}
|
39
13
|
]
|
40
14
|
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { fileURLToPath, URL } from "node:url"
|
2
|
+
|
3
|
+
import vue from "@vitejs/plugin-vue"
|
4
|
+
import { defineConfig } from "vite"
|
5
|
+
|
6
|
+
const env = process.env
|
7
|
+
const target = env.BACKEND_URL || "http://localhost:9292/"
|
8
|
+
const port = parseInt(env.port || "8080")
|
9
|
+
|
10
|
+
// https://vitejs.dev/config/
|
11
|
+
export default defineConfig({
|
12
|
+
plugins: [vue()],
|
13
|
+
server: {
|
14
|
+
port,
|
15
|
+
proxy: {
|
16
|
+
"/api": target
|
17
|
+
}
|
18
|
+
},
|
19
|
+
resolve: {
|
20
|
+
alias: {
|
21
|
+
"@": fileURLToPath(new URL("./src", import.meta.url))
|
22
|
+
}
|
23
|
+
}
|
24
|
+
})
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { fileURLToPath } from "node:url"
|
2
|
+
|
3
|
+
import { mergeConfig } from "vite"
|
4
|
+
import { configDefaults, defineConfig } from "vitest/config"
|
5
|
+
|
6
|
+
import viteConfig from "./vite.config"
|
7
|
+
|
8
|
+
export default mergeConfig(
|
9
|
+
viteConfig,
|
10
|
+
defineConfig({
|
11
|
+
test: {
|
12
|
+
environment: "jsdom",
|
13
|
+
exclude: [...configDefaults.exclude, "e2e/*"],
|
14
|
+
root: fileURLToPath(new URL("./", import.meta.url)),
|
15
|
+
transformMode: {
|
16
|
+
web: [/\.[jt]sx$/]
|
17
|
+
},
|
18
|
+
include: ["**/__tests__/**/*.?(c|m)[jt]s?(x)", "**/?(*.){test,spec}.?(c|m)[jt]s?(x)"]
|
19
|
+
}
|
20
|
+
})
|
21
|
+
)
|
data/lefthook.yml
CHANGED
@@ -3,8 +3,10 @@ pre-commit:
|
|
3
3
|
commands:
|
4
4
|
standard:
|
5
5
|
glob: "*.rb"
|
6
|
-
run: bundle exec standardrb --fix {staged_files}
|
6
|
+
run: bundle exec standardrb --fix {staged_files}
|
7
|
+
stage_fixed: true
|
7
8
|
eslint:
|
8
9
|
root: "frontend/"
|
9
10
|
glob: "*.{js,ts,vue}"
|
10
|
-
run: npx eslint --fix {staged_files}
|
11
|
+
run: npx eslint --fix {staged_files}
|
12
|
+
stage_fixed: true
|
@@ -3,11 +3,45 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Analyzers
|
5
5
|
class Base
|
6
|
-
extend Dry::Initializer
|
7
|
-
|
8
6
|
include Mixins::Configurable
|
9
7
|
include Mixins::Retriable
|
10
8
|
|
9
|
+
# @return [String]
|
10
|
+
attr_reader :query
|
11
|
+
|
12
|
+
# @return [Hash]
|
13
|
+
attr_reader :options
|
14
|
+
|
15
|
+
#
|
16
|
+
# @param [String] query
|
17
|
+
# @param [Hash, nil] options
|
18
|
+
#
|
19
|
+
def initialize(query, options: nil)
|
20
|
+
@query = query
|
21
|
+
@options = options || {}
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# @return [Integer, nil]
|
26
|
+
#
|
27
|
+
def interval
|
28
|
+
@interval = options[:interval]
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# @return [Integer]
|
33
|
+
#
|
34
|
+
def retry_interval
|
35
|
+
@retry_interval ||= options[:retry_interval] || DEFAULT_RETRY_INTERVAL
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# @return [Integer]
|
40
|
+
#
|
41
|
+
def retry_times
|
42
|
+
@retry_times ||= options[:retry_times] || DEFAULT_RETRY_TIMES
|
43
|
+
end
|
44
|
+
|
11
45
|
# @return [Array<String>, Array<Mihari::Artifact>]
|
12
46
|
def artifacts
|
13
47
|
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
@@ -21,17 +55,14 @@ module Mihari
|
|
21
55
|
# @return [Array<Mihari::Artifact>]
|
22
56
|
#
|
23
57
|
def normalized_artifacts
|
24
|
-
retry_on_error do
|
58
|
+
retry_on_error(times: retry_times, interval: retry_interval) do
|
25
59
|
@normalized_artifacts ||= artifacts.compact.sort.map do |artifact|
|
26
60
|
# No need to set data_type manually
|
27
61
|
# It is set automatically in #initialize
|
28
62
|
artifact = artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact)
|
29
|
-
artifact
|
30
|
-
end.select(&:valid?).uniq(&:data).map do |artifact|
|
31
|
-
# set source
|
32
63
|
artifact.source = source
|
33
64
|
artifact
|
34
|
-
end
|
65
|
+
end.select(&:valid?).uniq(&:data)
|
35
66
|
end
|
36
67
|
end
|
37
68
|
|
@@ -51,16 +82,19 @@ module Mihari
|
|
51
82
|
# @return [Mihari::Analyzers::Base]
|
52
83
|
#
|
53
84
|
def from_query(params)
|
54
|
-
|
55
|
-
|
85
|
+
copied = params.deep_dup
|
86
|
+
|
87
|
+
# convert params into arguments for initialization
|
88
|
+
query = copied[:query]
|
56
89
|
|
57
|
-
#
|
58
|
-
|
59
|
-
|
90
|
+
# delete analyzer and query
|
91
|
+
%i[analyzer query].each do |key|
|
92
|
+
copied.delete key
|
93
|
+
end
|
60
94
|
|
61
|
-
|
95
|
+
copied[:options] = copied[:options] || nil
|
62
96
|
|
63
|
-
new(query, **
|
97
|
+
new(query, **copied)
|
64
98
|
end
|
65
99
|
|
66
100
|
def inherited(child)
|