mihari 5.7.0 → 5.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/lib/mihari/actor.rb +10 -4
- data/lib/mihari/cli/main.rb +2 -0
- data/lib/mihari/clients/base.rb +23 -1
- data/lib/mihari/clients/binaryedge.rb +1 -3
- data/lib/mihari/clients/censys.rb +1 -2
- data/lib/mihari/clients/crtsh.rb +2 -3
- data/lib/mihari/clients/dnstwister.rb +1 -2
- data/lib/mihari/clients/fofa.rb +1 -3
- data/lib/mihari/clients/greynoise.rb +1 -2
- data/lib/mihari/clients/hunterhow.rb +1 -2
- data/lib/mihari/clients/misp.rb +1 -2
- data/lib/mihari/clients/onyphe.rb +1 -2
- data/lib/mihari/clients/otx.rb +2 -14
- data/lib/mihari/clients/passivetotal.rb +3 -16
- data/lib/mihari/clients/publsedive.rb +2 -17
- data/lib/mihari/clients/securitytrails.rb +3 -25
- data/lib/mihari/clients/shodan.rb +1 -2
- data/lib/mihari/clients/the_hive.rb +1 -2
- data/lib/mihari/clients/urlscan.rb +1 -2
- data/lib/mihari/clients/virustotal.rb +3 -17
- data/lib/mihari/clients/zoomeye.rb +9 -19
- data/lib/mihari/commands/alert.rb +11 -9
- data/lib/mihari/commands/database.rb +4 -1
- data/lib/mihari/commands/mixins.rb +11 -0
- data/lib/mihari/commands/search.rb +13 -32
- data/lib/mihari/constants.rb +1 -1
- data/lib/mihari/database.rb +1 -1
- data/lib/mihari/enrichers/ipinfo.rb +1 -1
- data/lib/mihari/entities/tag.rb +1 -0
- data/lib/mihari/http.rb +13 -11
- data/lib/mihari/rule.rb +14 -0
- data/lib/mihari/service.rb +12 -2
- data/lib/mihari/services/alert_builder.rb +81 -8
- data/lib/mihari/services/alert_runner.rb +3 -10
- data/lib/mihari/services/rule_builder.rb +8 -10
- data/lib/mihari/services/rule_runner.rb +2 -25
- data/lib/mihari/structs/binaryedge.rb +9 -0
- data/lib/mihari/structs/censys.rb +0 -14
- data/lib/mihari/structs/fofa.rb +3 -0
- data/lib/mihari/structs/google_public_dns.rb +0 -4
- data/lib/mihari/structs/greynoise.rb +0 -6
- data/lib/mihari/structs/hunterhow.rb +0 -6
- data/lib/mihari/structs/ipinfo.rb +0 -2
- data/lib/mihari/structs/onyphe.rb +0 -4
- data/lib/mihari/structs/shodan.rb +0 -2
- data/lib/mihari/structs/urlscan.rb +0 -6
- data/lib/mihari/structs/virustotal_intelligence.rb +0 -8
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +20 -17
- data/lib/mihari/web/endpoints/alerts.rb +75 -38
- data/lib/mihari/web/endpoints/artifacts.rb +60 -53
- data/lib/mihari/web/endpoints/ip_addresses.rb +19 -4
- data/lib/mihari/web/endpoints/rules.rb +132 -88
- data/lib/mihari/web/endpoints/tags.rb +15 -13
- data/lib/mihari/web/middleware/error_notification_adapter.rb +8 -3
- data/lib/mihari/web/public/assets/{index-821134e2.js → index-ec641cb0.js} +45 -44
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +400 -400
- data/lib/mihari.rb +0 -2
- data/mihari.gemspec +5 -5
- data/mkdocs.yml +14 -7
- metadata +13 -140
- data/docs/alternatives.md +0 -5
- data/docs/analyzers/binaryedge.md +0 -26
- data/docs/analyzers/censys.md +0 -31
- data/docs/analyzers/circl.md +0 -37
- data/docs/analyzers/crtsh.md +0 -26
- data/docs/analyzers/dnstwister.md +0 -25
- data/docs/analyzers/feed.md +0 -73
- data/docs/analyzers/fofa.md +0 -31
- data/docs/analyzers/greynoise.md +0 -26
- data/docs/analyzers/hunterhow.md +0 -33
- data/docs/analyzers/index.md +0 -104
- data/docs/analyzers/onyphe.md +0 -26
- data/docs/analyzers/otx.md +0 -28
- data/docs/analyzers/passivetotal.md +0 -52
- data/docs/analyzers/pulsedive.md +0 -28
- data/docs/analyzers/securitytrails.md +0 -41
- data/docs/analyzers/shodan.md +0 -26
- data/docs/analyzers/urlscan.md +0 -28
- data/docs/analyzers/virustotal.md +0 -43
- data/docs/analyzers/virustotal_intelligence.md +0 -33
- data/docs/analyzers/zoomeye.md +0 -38
- data/docs/configuration.md +0 -35
- data/docs/emitters/database.md +0 -22
- data/docs/emitters/hive.md +0 -26
- data/docs/emitters/index.md +0 -36
- data/docs/emitters/misp.md +0 -21
- data/docs/emitters/slack.md +0 -21
- data/docs/emitters/webhook.md +0 -63
- data/docs/enrichers/google_public_dns.md +0 -19
- data/docs/enrichers/index.md +0 -35
- data/docs/enrichers/ipinfo.md +0 -26
- data/docs/enrichers/shodan.md +0 -22
- data/docs/enrichers/whois.md +0 -17
- data/docs/github_actions.md +0 -43
- data/docs/index.md +0 -11
- data/docs/installation.md +0 -31
- data/docs/requirements.md +0 -13
- data/docs/rule.md +0 -168
- data/docs/tags.md +0 -3
- data/docs/usage.md +0 -103
- data/frontend/.eslintrc.cjs +0 -22
- data/frontend/.gitignore +0 -31
- data/frontend/.prettierrc.json +0 -8
- data/frontend/README.md +0 -3
- data/frontend/env.d.ts +0 -5
- data/frontend/index.html +0 -21
- data/frontend/package-lock.json +0 -7219
- data/frontend/package.json +0 -67
- data/frontend/public/favicon.ico +0 -0
- data/frontend/scripts/swagger_doc_to_yaml.rb +0 -23
- data/frontend/src/App.vue +0 -27
- data/frontend/src/ace-config.ts +0 -6
- data/frontend/src/api-helper.ts +0 -111
- data/frontend/src/api.ts +0 -105
- data/frontend/src/components/ErrorMessage.vue +0 -31
- data/frontend/src/components/Loading.vue +0 -15
- data/frontend/src/components/Navbar.vue +0 -42
- data/frontend/src/components/Pagination.vue +0 -119
- data/frontend/src/components/alert/Alert.vue +0 -87
- data/frontend/src/components/alert/Alerts.vue +0 -63
- data/frontend/src/components/alert/AlertsWithPagination.vue +0 -90
- data/frontend/src/components/alert/AlertsWrapper.vue +0 -128
- data/frontend/src/components/alert/Form.vue +0 -169
- data/frontend/src/components/artifact/AS.vue +0 -23
- data/frontend/src/components/artifact/Artifact.vue +0 -287
- data/frontend/src/components/artifact/ArtifactTag.vue +0 -64
- data/frontend/src/components/artifact/ArtifactTags.vue +0 -29
- data/frontend/src/components/artifact/ArtifactWrapper.vue +0 -57
- data/frontend/src/components/artifact/CPEs.vue +0 -23
- data/frontend/src/components/artifact/DnsRecords.vue +0 -32
- data/frontend/src/components/artifact/Ports.vue +0 -23
- data/frontend/src/components/artifact/ReverseDnsNames.vue +0 -23
- data/frontend/src/components/artifact/Tags.vue +0 -29
- data/frontend/src/components/artifact/WhoisRecord.vue +0 -44
- data/frontend/src/components/config/Configs.vue +0 -65
- data/frontend/src/components/config/ConfigsWrapper.vue +0 -32
- data/frontend/src/components/link/Link.vue +0 -32
- data/frontend/src/components/link/Links.vue +0 -42
- data/frontend/src/components/rule/EditRule.vue +0 -72
- data/frontend/src/components/rule/EditRuleWrapper.vue +0 -48
- data/frontend/src/components/rule/Form.vue +0 -158
- data/frontend/src/components/rule/InputForm.vue +0 -45
- data/frontend/src/components/rule/NewRule.vue +0 -57
- data/frontend/src/components/rule/Rule.vue +0 -100
- data/frontend/src/components/rule/RuleWrapper.vue +0 -53
- data/frontend/src/components/rule/Rules.vue +0 -84
- data/frontend/src/components/rule/RulesWrapper.vue +0 -121
- data/frontend/src/components/rule/YAML.vue +0 -37
- data/frontend/src/components/tag/Tag.vue +0 -65
- data/frontend/src/components/tag/Tags.vue +0 -37
- data/frontend/src/countries.ts +0 -350
- data/frontend/src/index.ts +0 -20
- data/frontend/src/links/anyrun.ts +0 -19
- data/frontend/src/links/base.ts +0 -14
- data/frontend/src/links/censys.ts +0 -20
- data/frontend/src/links/crtsh.ts +0 -20
- data/frontend/src/links/dnslytics.ts +0 -38
- data/frontend/src/links/greynoise.ts +0 -20
- data/frontend/src/links/index.ts +0 -40
- data/frontend/src/links/intezer.ts +0 -20
- data/frontend/src/links/otx.ts +0 -33
- data/frontend/src/links/securitytrails.ts +0 -38
- data/frontend/src/links/shodan.ts +0 -20
- data/frontend/src/links/urlscan.ts +0 -50
- data/frontend/src/links/virustotal.ts +0 -72
- data/frontend/src/main.ts +0 -41
- data/frontend/src/router/index.ts +0 -57
- data/frontend/src/rule.ts +0 -14
- data/frontend/src/shims-vue.d.ts +0 -6
- data/frontend/src/swagger.yaml +0 -771
- data/frontend/src/types.ts +0 -188
- data/frontend/src/utils.ts +0 -54
- data/frontend/src/views/Alerts.vue +0 -20
- data/frontend/src/views/Artifact.vue +0 -39
- data/frontend/src/views/Configs.vue +0 -20
- data/frontend/src/views/EditRule.vue +0 -39
- data/frontend/src/views/NewRule.vue +0 -26
- data/frontend/src/views/Rule.vue +0 -39
- data/frontend/src/views/Rules.vue +0 -20
- data/frontend/tests/utils.spec.ts +0 -9
- data/frontend/tsconfig.app.json +0 -21
- data/frontend/tsconfig.json +0 -14
- data/frontend/tsconfig.node.json +0 -13
- data/frontend/tsconfig.vitest.json +0 -12
- data/frontend/vite.config.ts +0 -24
- data/frontend/vitest.config.ts +0 -21
- data/lib/mihari/mixins/error_notification.rb +0 -21
- data/lib/mihari/services/alert_proxy.rb +0 -97
data/frontend/src/types.ts
DELETED
@@ -1,188 +0,0 @@
|
|
1
|
-
export interface Pagination {
|
2
|
-
total: number
|
3
|
-
currentPage: number
|
4
|
-
pageSize: number
|
5
|
-
}
|
6
|
-
|
7
|
-
export interface ConfigValue {
|
8
|
-
key: string
|
9
|
-
value: string | null
|
10
|
-
}
|
11
|
-
|
12
|
-
export interface Config {
|
13
|
-
name: string
|
14
|
-
isConfigured: boolean
|
15
|
-
values: ConfigValue[]
|
16
|
-
type: string
|
17
|
-
}
|
18
|
-
|
19
|
-
export interface Tag {
|
20
|
-
name: string
|
21
|
-
}
|
22
|
-
|
23
|
-
export interface Tags {
|
24
|
-
tags: string[]
|
25
|
-
}
|
26
|
-
|
27
|
-
export interface RuleSet {
|
28
|
-
ruleIds: string[]
|
29
|
-
}
|
30
|
-
|
31
|
-
export interface DnsRecord {
|
32
|
-
resource: string
|
33
|
-
value: string
|
34
|
-
}
|
35
|
-
|
36
|
-
export interface Contact {
|
37
|
-
name: string | null
|
38
|
-
organization: string | null
|
39
|
-
}
|
40
|
-
|
41
|
-
export interface Registrar {
|
42
|
-
name: string | null
|
43
|
-
organization: string | null
|
44
|
-
}
|
45
|
-
|
46
|
-
export interface WhoisRecord {
|
47
|
-
createdOn: Date | null
|
48
|
-
updatedOn: Date | null
|
49
|
-
expiresOn: Date | null
|
50
|
-
registrar: Registrar | null
|
51
|
-
contacts: Contact[]
|
52
|
-
}
|
53
|
-
|
54
|
-
export interface AutonomousSystem {
|
55
|
-
asn: number
|
56
|
-
}
|
57
|
-
|
58
|
-
export interface Geolocation {
|
59
|
-
country: string
|
60
|
-
countryCode: string
|
61
|
-
}
|
62
|
-
|
63
|
-
export interface ReverseDnsName {
|
64
|
-
name: string
|
65
|
-
}
|
66
|
-
|
67
|
-
export interface CPE {
|
68
|
-
cpe: string
|
69
|
-
}
|
70
|
-
|
71
|
-
export interface Port {
|
72
|
-
port: string
|
73
|
-
}
|
74
|
-
|
75
|
-
export interface Artifact {
|
76
|
-
id: string
|
77
|
-
data: string
|
78
|
-
dataType: string
|
79
|
-
source: string
|
80
|
-
metadata: unknown | null
|
81
|
-
createdAt: string
|
82
|
-
|
83
|
-
autonomousSystem: AutonomousSystem | null
|
84
|
-
whoisRecord: WhoisRecord | null
|
85
|
-
geolocation: Geolocation | null
|
86
|
-
|
87
|
-
dnsRecords: DnsRecord[] | null
|
88
|
-
reverseDnsNames: ReverseDnsName[] | null
|
89
|
-
cpes: CPE[] | null
|
90
|
-
ports: Port[] | null
|
91
|
-
}
|
92
|
-
|
93
|
-
export interface ArtifactWithTags extends Artifact {
|
94
|
-
tags: string[]
|
95
|
-
}
|
96
|
-
|
97
|
-
export interface Alert {
|
98
|
-
id: string
|
99
|
-
ruleId: string
|
100
|
-
createdAt: string
|
101
|
-
|
102
|
-
tags: Tag[]
|
103
|
-
artifacts: Artifact[]
|
104
|
-
}
|
105
|
-
|
106
|
-
export interface Alerts extends Pagination {
|
107
|
-
alerts: Alert[]
|
108
|
-
}
|
109
|
-
|
110
|
-
export interface PaginationParams {
|
111
|
-
page: number | undefined
|
112
|
-
}
|
113
|
-
|
114
|
-
export interface AlertSearchParams extends PaginationParams {
|
115
|
-
artifact: string | undefined
|
116
|
-
ruleId: string | undefined
|
117
|
-
tag: string | undefined
|
118
|
-
fromAt: string | undefined
|
119
|
-
toAt: string | undefined
|
120
|
-
}
|
121
|
-
|
122
|
-
export interface IPInfo {
|
123
|
-
ip: string
|
124
|
-
hostname: string | null
|
125
|
-
loc: string
|
126
|
-
countryCode: string
|
127
|
-
asn: string
|
128
|
-
}
|
129
|
-
|
130
|
-
export interface GCS {
|
131
|
-
lat: number
|
132
|
-
long: number
|
133
|
-
}
|
134
|
-
|
135
|
-
export interface Country {
|
136
|
-
name: string
|
137
|
-
code: string
|
138
|
-
lat: number
|
139
|
-
long: number
|
140
|
-
}
|
141
|
-
|
142
|
-
export type LinkType = "ip" | "domain" | "url" | "hash"
|
143
|
-
|
144
|
-
export interface Link {
|
145
|
-
name: string
|
146
|
-
type: string
|
147
|
-
baseURL: string
|
148
|
-
// eslint-disable-next-line no-unused-vars
|
149
|
-
href(data: string): string
|
150
|
-
favicon(): string
|
151
|
-
}
|
152
|
-
|
153
|
-
export interface Rule {
|
154
|
-
id: string
|
155
|
-
title: string
|
156
|
-
description: string
|
157
|
-
yaml: string
|
158
|
-
createdAt: string
|
159
|
-
updatedAt: string
|
160
|
-
tags: Tag[]
|
161
|
-
}
|
162
|
-
|
163
|
-
export interface CreateRule {
|
164
|
-
yaml: string
|
165
|
-
}
|
166
|
-
|
167
|
-
export interface UpdateRule {
|
168
|
-
id: string
|
169
|
-
yaml: string
|
170
|
-
}
|
171
|
-
|
172
|
-
export interface Query {
|
173
|
-
analyzer: string
|
174
|
-
query: string
|
175
|
-
interval: null
|
176
|
-
}
|
177
|
-
|
178
|
-
export interface Rules extends Pagination {
|
179
|
-
rules: Rule[]
|
180
|
-
}
|
181
|
-
|
182
|
-
export interface RuleSearchParams extends PaginationParams {
|
183
|
-
description: string | undefined
|
184
|
-
tag: string | undefined
|
185
|
-
title: string | undefined
|
186
|
-
fromAt: string | undefined
|
187
|
-
toAt: string | undefined
|
188
|
-
}
|
data/frontend/src/utils.ts
DELETED
@@ -1,54 +0,0 @@
|
|
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
|
-
|
7
|
-
import { getCountryByCode } from "@/countries"
|
8
|
-
import type { GCS, IPInfo } from "@/types"
|
9
|
-
|
10
|
-
dayjs.extend(relativeTime)
|
11
|
-
dayjs.extend(timezone)
|
12
|
-
dayjs.extend(utc)
|
13
|
-
|
14
|
-
export function getLocalDatetime(datetime: string): string {
|
15
|
-
return dayjs(datetime).local().format("YYYY-MM-DD HH:mm:ss")
|
16
|
-
}
|
17
|
-
|
18
|
-
export function getHumanizedRelativeTime(datetime: string): string {
|
19
|
-
return dayjs(datetime).local().fromNow()
|
20
|
-
}
|
21
|
-
|
22
|
-
export function getGCSByCountryCode(countryCode: string): GCS | undefined {
|
23
|
-
const country = getCountryByCode(countryCode)
|
24
|
-
if (country !== undefined) {
|
25
|
-
return { lat: country.lat, long: country.long }
|
26
|
-
}
|
27
|
-
}
|
28
|
-
|
29
|
-
export function getGCSByIPInfo(ipinfo: IPInfo): GCS | undefined {
|
30
|
-
if (ipinfo.loc !== undefined) {
|
31
|
-
const numbers = ipinfo.loc.split(",")
|
32
|
-
if (numbers.length === 2) {
|
33
|
-
const lat = numbers[0]
|
34
|
-
const long = numbers[1]
|
35
|
-
|
36
|
-
return { lat: parseFloat(lat), long: parseFloat(long) }
|
37
|
-
}
|
38
|
-
}
|
39
|
-
return getGCSByCountryCode(ipinfo.countryCode)
|
40
|
-
}
|
41
|
-
|
42
|
-
export function normalizeQueryParam(
|
43
|
-
param: undefined | null | string | string[] | LocationQueryValue | LocationQueryValue[]
|
44
|
-
): string | undefined {
|
45
|
-
if (param === undefined || param === null) {
|
46
|
-
return undefined
|
47
|
-
}
|
48
|
-
|
49
|
-
if (typeof param === "string") {
|
50
|
-
return param
|
51
|
-
}
|
52
|
-
|
53
|
-
return param.toString()
|
54
|
-
}
|
@@ -1,20 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<Alerts></Alerts>
|
3
|
-
</template>
|
4
|
-
|
5
|
-
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent } from "vue"
|
8
|
-
|
9
|
-
import Alerts from "@/components/alert/AlertsWrapper.vue"
|
10
|
-
|
11
|
-
export default defineComponent({
|
12
|
-
name: "AlertsView",
|
13
|
-
components: {
|
14
|
-
Alerts
|
15
|
-
},
|
16
|
-
setup() {
|
17
|
-
useTitle("Alerts - Mihari")
|
18
|
-
}
|
19
|
-
})
|
20
|
-
</script>
|
@@ -1,39 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<Artifact :id="id"></Artifact>
|
3
|
-
</template>
|
4
|
-
|
5
|
-
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent, onMounted, watch } from "vue"
|
8
|
-
|
9
|
-
import Artifact from "@/components/artifact/ArtifactWrapper.vue"
|
10
|
-
|
11
|
-
export default defineComponent({
|
12
|
-
name: "ArtifactView",
|
13
|
-
components: {
|
14
|
-
Artifact
|
15
|
-
},
|
16
|
-
props: {
|
17
|
-
id: {
|
18
|
-
type: String,
|
19
|
-
required: true
|
20
|
-
}
|
21
|
-
},
|
22
|
-
setup(props) {
|
23
|
-
const updateTitle = () => {
|
24
|
-
useTitle(`Artifact:${props.id} - Mihari`)
|
25
|
-
}
|
26
|
-
|
27
|
-
onMounted(() => {
|
28
|
-
updateTitle()
|
29
|
-
})
|
30
|
-
|
31
|
-
watch(
|
32
|
-
() => props.id,
|
33
|
-
() => {
|
34
|
-
updateTitle()
|
35
|
-
}
|
36
|
-
)
|
37
|
-
}
|
38
|
-
})
|
39
|
-
</script>
|
@@ -1,20 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<Configs></Configs>
|
3
|
-
</template>
|
4
|
-
|
5
|
-
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent } from "vue"
|
8
|
-
|
9
|
-
import Configs from "@/components/config/ConfigsWrapper.vue"
|
10
|
-
|
11
|
-
export default defineComponent({
|
12
|
-
name: "ConfigView",
|
13
|
-
components: {
|
14
|
-
Configs
|
15
|
-
},
|
16
|
-
setup() {
|
17
|
-
useTitle("Config - Mihari")
|
18
|
-
}
|
19
|
-
})
|
20
|
-
</script>
|
@@ -1,39 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<EditRule :id="id"></EditRule>
|
3
|
-
</template>
|
4
|
-
|
5
|
-
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent, onMounted, watch } from "vue"
|
8
|
-
|
9
|
-
import EditRule from "@/components/rule/EditRuleWrapper.vue"
|
10
|
-
|
11
|
-
export default defineComponent({
|
12
|
-
name: "EditRuleView",
|
13
|
-
components: {
|
14
|
-
EditRule
|
15
|
-
},
|
16
|
-
props: {
|
17
|
-
id: {
|
18
|
-
type: String,
|
19
|
-
required: true
|
20
|
-
}
|
21
|
-
},
|
22
|
-
setup(props) {
|
23
|
-
const updateTitle = () => {
|
24
|
-
useTitle(`Edit rule:${props.id} - Mihari`)
|
25
|
-
}
|
26
|
-
|
27
|
-
onMounted(() => {
|
28
|
-
updateTitle()
|
29
|
-
})
|
30
|
-
|
31
|
-
watch(
|
32
|
-
() => props.id,
|
33
|
-
() => {
|
34
|
-
updateTitle()
|
35
|
-
}
|
36
|
-
)
|
37
|
-
}
|
38
|
-
})
|
39
|
-
</script>
|
@@ -1,26 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<NewRule></NewRule>
|
3
|
-
</template>
|
4
|
-
|
5
|
-
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent, onMounted } from "vue"
|
8
|
-
|
9
|
-
import NewRule from "@/components/rule/NewRule.vue"
|
10
|
-
|
11
|
-
export default defineComponent({
|
12
|
-
name: "NewRuleView",
|
13
|
-
components: {
|
14
|
-
NewRule
|
15
|
-
},
|
16
|
-
setup() {
|
17
|
-
const updateTitle = () => {
|
18
|
-
useTitle(`New rule - Mihari`)
|
19
|
-
}
|
20
|
-
|
21
|
-
onMounted(() => {
|
22
|
-
updateTitle()
|
23
|
-
})
|
24
|
-
}
|
25
|
-
})
|
26
|
-
</script>
|
data/frontend/src/views/Rule.vue
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<Rule :id="id"></Rule>
|
3
|
-
</template>
|
4
|
-
|
5
|
-
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent, onMounted, watch } from "vue"
|
8
|
-
|
9
|
-
import Rule from "@/components/rule/RuleWrapper.vue"
|
10
|
-
|
11
|
-
export default defineComponent({
|
12
|
-
name: "RuleView",
|
13
|
-
components: {
|
14
|
-
Rule
|
15
|
-
},
|
16
|
-
props: {
|
17
|
-
id: {
|
18
|
-
type: String,
|
19
|
-
required: true
|
20
|
-
}
|
21
|
-
},
|
22
|
-
setup(props) {
|
23
|
-
const updateTitle = () => {
|
24
|
-
useTitle(`Rule:${props.id} - Mihari`)
|
25
|
-
}
|
26
|
-
|
27
|
-
onMounted(() => {
|
28
|
-
updateTitle()
|
29
|
-
})
|
30
|
-
|
31
|
-
watch(
|
32
|
-
() => props.id,
|
33
|
-
() => {
|
34
|
-
updateTitle()
|
35
|
-
}
|
36
|
-
)
|
37
|
-
}
|
38
|
-
})
|
39
|
-
</script>
|
@@ -1,20 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<Rules></Rules>
|
3
|
-
</template>
|
4
|
-
|
5
|
-
<script lang="ts">
|
6
|
-
import { useTitle } from "@vueuse/core"
|
7
|
-
import { defineComponent } from "vue"
|
8
|
-
|
9
|
-
import Rules from "@/components/rule/RulesWrapper.vue"
|
10
|
-
|
11
|
-
export default defineComponent({
|
12
|
-
name: "RulesView",
|
13
|
-
components: {
|
14
|
-
Rules
|
15
|
-
},
|
16
|
-
setup() {
|
17
|
-
useTitle("Rules - Mihari")
|
18
|
-
}
|
19
|
-
})
|
20
|
-
</script>
|
@@ -1,9 +0,0 @@
|
|
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
|
-
})
|
data/frontend/tsconfig.app.json
DELETED
@@ -1,21 +0,0 @@
|
|
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
DELETED
data/frontend/tsconfig.node.json
DELETED
data/frontend/vite.config.ts
DELETED
@@ -1,24 +0,0 @@
|
|
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
|
-
})
|
data/frontend/vitest.config.ts
DELETED
@@ -1,21 +0,0 @@
|
|
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
|
-
)
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Mixins
|
5
|
-
#
|
6
|
-
# Error notification mixin
|
7
|
-
#
|
8
|
-
module ErrorNotification
|
9
|
-
#
|
10
|
-
# Send an exception notification if there is any error in a block
|
11
|
-
#
|
12
|
-
def with_error_notification
|
13
|
-
yield
|
14
|
-
rescue StandardError => e
|
15
|
-
Mihari.logger.error e
|
16
|
-
|
17
|
-
Sentry.capture_exception(e) if Sentry.initialized?
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "json"
|
4
|
-
|
5
|
-
module Mihari
|
6
|
-
module Services
|
7
|
-
#
|
8
|
-
# Alert proxy
|
9
|
-
#
|
10
|
-
class AlertProxy < Service
|
11
|
-
# @return [Hash]
|
12
|
-
attr_reader :data
|
13
|
-
|
14
|
-
# @return [Array, nil]
|
15
|
-
attr_reader :errors
|
16
|
-
|
17
|
-
#
|
18
|
-
# Initialize
|
19
|
-
#
|
20
|
-
# @param [Hash] data
|
21
|
-
#
|
22
|
-
def initialize(**data)
|
23
|
-
super()
|
24
|
-
|
25
|
-
@data = data.deep_symbolize_keys
|
26
|
-
@errors = nil
|
27
|
-
|
28
|
-
validate!
|
29
|
-
end
|
30
|
-
|
31
|
-
#
|
32
|
-
# @return [Boolean]
|
33
|
-
#
|
34
|
-
def errors?
|
35
|
-
return false if @errors.nil?
|
36
|
-
|
37
|
-
!@errors.empty?
|
38
|
-
end
|
39
|
-
|
40
|
-
def validate!
|
41
|
-
contract = Schemas::AlertContract.new
|
42
|
-
result = contract.call(data)
|
43
|
-
|
44
|
-
@data = result.to_h
|
45
|
-
@errors = result.errors
|
46
|
-
|
47
|
-
raise ValidationError.new("Validation failed", errors) if errors?
|
48
|
-
end
|
49
|
-
|
50
|
-
def [](key)
|
51
|
-
data key.to_sym
|
52
|
-
end
|
53
|
-
|
54
|
-
#
|
55
|
-
# @return [String]
|
56
|
-
#
|
57
|
-
def rule_id
|
58
|
-
@rule_id ||= data[:rule_id]
|
59
|
-
end
|
60
|
-
|
61
|
-
#
|
62
|
-
# @return [Array<Mihari::Models::Artifact>]
|
63
|
-
#
|
64
|
-
def artifacts
|
65
|
-
@artifacts ||= data[:artifacts].map do |data|
|
66
|
-
artifact = Models::Artifact.new(data: data)
|
67
|
-
artifact.rule_id = rule_id
|
68
|
-
artifact
|
69
|
-
end.uniq(&:data).select(&:valid?)
|
70
|
-
end
|
71
|
-
|
72
|
-
#
|
73
|
-
# @return [Mihari::Rule]
|
74
|
-
#
|
75
|
-
def rule
|
76
|
-
@rule ||= [].tap do |out|
|
77
|
-
data = Mihari::Models::Rule.find(rule_id).data
|
78
|
-
out << Rule.new(**data)
|
79
|
-
end.first
|
80
|
-
end
|
81
|
-
|
82
|
-
class << self
|
83
|
-
#
|
84
|
-
# Load rule from YAML string
|
85
|
-
#
|
86
|
-
# @param [String] yaml
|
87
|
-
#
|
88
|
-
# @return [Mihari::Services::Alert]
|
89
|
-
#
|
90
|
-
def from_yaml(yaml)
|
91
|
-
data = YAML.safe_load(yaml, permitted_classes: [Date, Symbol])
|
92
|
-
new(**data)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|