mihari 5.7.0 → 5.7.1
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/commands/alert.rb +6 -4
- data/lib/mihari/commands/search.rb +10 -29
- data/lib/mihari/enrichers/ipinfo.rb +1 -1
- data/lib/mihari/entities/tag.rb +1 -0
- 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/public/assets/{index-821134e2.js → index-07fafab5.js} +4 -3
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari.rb +0 -1
- data/mihari.gemspec +1 -1
- data/mkdocs.yml +1 -0
- metadata +3 -130
- 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/services/alert_proxy.rb +0 -97
data/frontend/package.json
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"name": "mihari",
|
3
|
-
"version": "0.1.0",
|
4
|
-
"private": true,
|
5
|
-
"scripts": {
|
6
|
-
"build-only": "vite build",
|
7
|
-
"build-redoc": "npx @redocly/cli build-docs src/swagger.yaml -o public/redoc-static.html",
|
8
|
-
"build": "run-p type-check build-only build-redoc",
|
9
|
-
"dev": "vite",
|
10
|
-
"format": "prettier --write src/",
|
11
|
-
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
12
|
-
"preview": "vite preview",
|
13
|
-
"test:unit": "vitest",
|
14
|
-
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false"
|
15
|
-
},
|
16
|
-
"dependencies": {
|
17
|
-
"@fortawesome/fontawesome-svg-core": "^6.4.2",
|
18
|
-
"@fortawesome/free-solid-svg-icons": "^6.4.2",
|
19
|
-
"@fortawesome/vue-fontawesome": "^3.0.3",
|
20
|
-
"@vueuse/core": "^10.5.0",
|
21
|
-
"@vueuse/router": "^10.5.0",
|
22
|
-
"ace-builds": "^1.31.1",
|
23
|
-
"axios": "^1.6.0",
|
24
|
-
"bulma": "^0.9.4",
|
25
|
-
"bulma-helpers": "^0.4.3",
|
26
|
-
"dayjs": "^1.11.10",
|
27
|
-
"font-awesome-animation": "^1.1.1",
|
28
|
-
"js-sha256": "^0.10.1",
|
29
|
-
"truncate": "^3.0.0",
|
30
|
-
"ts-dedent": "^2.2.0",
|
31
|
-
"url-parse": "^1.5.10",
|
32
|
-
"uuidv4": "^6.2.13",
|
33
|
-
"vue": "^3.3.7",
|
34
|
-
"vue-concurrency": "4.0.1",
|
35
|
-
"vue-json-pretty": "^2.2.4",
|
36
|
-
"vue-router": "^4.2.5",
|
37
|
-
"vue3-ace-editor": "^2.2.4"
|
38
|
-
},
|
39
|
-
"devDependencies": {
|
40
|
-
"@redocly/cli": "1.4.0",
|
41
|
-
"@rushstack/eslint-patch": "^1.5.1",
|
42
|
-
"@tsconfig/node20": "^20.1.2",
|
43
|
-
"@types/jsdom": "^21.1.4",
|
44
|
-
"@types/node": "^20.8.10",
|
45
|
-
"@types/url-parse": "^1.4.10",
|
46
|
-
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
47
|
-
"@typescript-eslint/parser": "^6.9.1",
|
48
|
-
"@vitejs/plugin-vue": "^4.4.0",
|
49
|
-
"@vue/eslint-config-prettier": "^8.0.0",
|
50
|
-
"@vue/eslint-config-typescript": "^12.0.0",
|
51
|
-
"@vue/test-utils": "2.4.1",
|
52
|
-
"@vue/tsconfig": "^0.4.0",
|
53
|
-
"eslint": "^8.52.0",
|
54
|
-
"eslint-config-prettier": "^9.0.0",
|
55
|
-
"eslint-plugin-prettier": "^5.0.1",
|
56
|
-
"eslint-plugin-simple-import-sort": "^10.0.0",
|
57
|
-
"eslint-plugin-vue": "^9.18.1",
|
58
|
-
"husky": "^8.0.3",
|
59
|
-
"jsdom": "^22.1.0",
|
60
|
-
"npm-run-all": "^4.1.5",
|
61
|
-
"prettier": "^3.0.3",
|
62
|
-
"typescript": "~5.2.2",
|
63
|
-
"vite": "^4.5.0",
|
64
|
-
"vitest": "^0.34.6",
|
65
|
-
"vue-tsc": "^1.8.22"
|
66
|
-
}
|
67
|
-
}
|
data/frontend/public/favicon.ico
DELETED
Binary file
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require "http"
|
2
|
-
require "json"
|
3
|
-
require "yaml"
|
4
|
-
|
5
|
-
def recursive_delete(hash, to_remove)
|
6
|
-
hash.delete(to_remove)
|
7
|
-
hash.each_value do |value|
|
8
|
-
recursive_delete(value, to_remove) if value.is_a? Hash
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
res = HTTP.get("http://localhost:9292/api/swagger_doc")
|
13
|
-
json = JSON.parse(res.body.to_s)
|
14
|
-
|
15
|
-
# remove host and operationId because
|
16
|
-
# - host: can be varied
|
17
|
-
# - operationId: is useless (to me)
|
18
|
-
keys_to_remove = ["host", "operationId"]
|
19
|
-
keys_to_remove.each do |key|
|
20
|
-
recursive_delete json, key
|
21
|
-
end
|
22
|
-
|
23
|
-
puts json.to_yaml
|
data/frontend/src/App.vue
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<Navbar></Navbar>
|
3
|
-
<section class="section is-medium">
|
4
|
-
<div class="container">
|
5
|
-
<router-view />
|
6
|
-
</div>
|
7
|
-
</section>
|
8
|
-
</template>
|
9
|
-
|
10
|
-
<script lang="ts">
|
11
|
-
import { defineComponent } from "vue"
|
12
|
-
|
13
|
-
import Navbar from "@/components/Navbar.vue"
|
14
|
-
|
15
|
-
export default defineComponent({
|
16
|
-
name: "App",
|
17
|
-
components: {
|
18
|
-
Navbar
|
19
|
-
}
|
20
|
-
})
|
21
|
-
</script>
|
22
|
-
|
23
|
-
<style>
|
24
|
-
table.is-fullwidth th {
|
25
|
-
width: 120px;
|
26
|
-
}
|
27
|
-
</style>
|
data/frontend/src/ace-config.ts
DELETED
@@ -1,6 +0,0 @@
|
|
1
|
-
import ace from "ace-builds"
|
2
|
-
import modeYamlUrl from "ace-builds/src-min-noconflict/mode-yaml?url"
|
3
|
-
import themeMonokaiUrl from "ace-builds/src-min-noconflict/theme-monokai?url"
|
4
|
-
|
5
|
-
ace.config.setModuleUrl("ace/mode/yaml", modeYamlUrl)
|
6
|
-
ace.config.setModuleUrl("ace/theme/monokai", themeMonokaiUrl)
|
data/frontend/src/api-helper.ts
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
import { type Task, useAsyncTask } from "vue-concurrency"
|
2
|
-
|
3
|
-
import { API } from "@/api"
|
4
|
-
import type {
|
5
|
-
Alerts,
|
6
|
-
AlertSearchParams,
|
7
|
-
ArtifactWithTags,
|
8
|
-
Config,
|
9
|
-
CreateRule,
|
10
|
-
IPInfo,
|
11
|
-
Rule,
|
12
|
-
Rules,
|
13
|
-
RuleSearchParams,
|
14
|
-
UpdateRule
|
15
|
-
} from "@/types"
|
16
|
-
|
17
|
-
export function generateGetAlertsTask(): Task<Alerts, [AlertSearchParams]> {
|
18
|
-
return useAsyncTask<Alerts, [AlertSearchParams]>(async (_signal, params) => {
|
19
|
-
return await API.getAlerts(params)
|
20
|
-
})
|
21
|
-
}
|
22
|
-
|
23
|
-
export function generateDeleteAlertTask(): Task<void, [string]> {
|
24
|
-
return useAsyncTask<void, [string]>(async (_signal, id) => {
|
25
|
-
return await API.deleteAlert(id)
|
26
|
-
})
|
27
|
-
}
|
28
|
-
|
29
|
-
export function generateGetTagsTask(): Task<string[], []> {
|
30
|
-
return useAsyncTask<string[], []>(async () => {
|
31
|
-
return await API.getTags()
|
32
|
-
})
|
33
|
-
}
|
34
|
-
|
35
|
-
export function generateDeleteTagTask(): Task<void, [string]> {
|
36
|
-
return useAsyncTask<void, [string]>(async (_signal, tag) => {
|
37
|
-
return await API.deleteTag(tag)
|
38
|
-
})
|
39
|
-
}
|
40
|
-
|
41
|
-
export function generateGetRuleSetTask(): Task<string[], []> {
|
42
|
-
return useAsyncTask<string[], []>(async () => {
|
43
|
-
return await API.getRuleSet()
|
44
|
-
})
|
45
|
-
}
|
46
|
-
|
47
|
-
export function generateGetArtifactTask(): Task<ArtifactWithTags, [string]> {
|
48
|
-
return useAsyncTask<ArtifactWithTags, [string]>(async (_signal, id) => {
|
49
|
-
return await API.getArtifact(id)
|
50
|
-
})
|
51
|
-
}
|
52
|
-
|
53
|
-
export function generateDeleteArtifactTask(): Task<void, [string]> {
|
54
|
-
return useAsyncTask<void, [string]>(async (_signal, id) => {
|
55
|
-
return await API.deleteArtifact(id)
|
56
|
-
})
|
57
|
-
}
|
58
|
-
|
59
|
-
export function generateEnrichArtifactTask(): Task<void, [string]> {
|
60
|
-
return useAsyncTask<void, [string]>(async (_signal, id) => {
|
61
|
-
return await API.enrichArtifact(id)
|
62
|
-
})
|
63
|
-
}
|
64
|
-
|
65
|
-
export function generateGetConfigsTask(): Task<Config[], []> {
|
66
|
-
return useAsyncTask<Config[], []>(async () => {
|
67
|
-
return await API.getConfigs()
|
68
|
-
})
|
69
|
-
}
|
70
|
-
|
71
|
-
export function generateGetIPTask(): Task<IPInfo, [string]> {
|
72
|
-
return useAsyncTask<IPInfo, [string]>(async (_signal, ipAddress: string) => {
|
73
|
-
return await API.getIPInfo(ipAddress)
|
74
|
-
})
|
75
|
-
}
|
76
|
-
|
77
|
-
export function generateGetRulesTask(): Task<Rules, [RuleSearchParams]> {
|
78
|
-
return useAsyncTask<Rules, [RuleSearchParams]>(async (_signal, params: RuleSearchParams) => {
|
79
|
-
return await API.getRules(params)
|
80
|
-
})
|
81
|
-
}
|
82
|
-
|
83
|
-
export function generateGetRuleTask(): Task<Rule, [string]> {
|
84
|
-
return useAsyncTask<Rule, [string]>(async (_signal, id: string) => {
|
85
|
-
return await API.getRule(id)
|
86
|
-
})
|
87
|
-
}
|
88
|
-
|
89
|
-
export function generateDeleteRuleTask(): Task<void, [string]> {
|
90
|
-
return useAsyncTask<void, [string]>(async (_signal, id: string) => {
|
91
|
-
return await API.deleteRule(id)
|
92
|
-
})
|
93
|
-
}
|
94
|
-
|
95
|
-
export function generateRunRuleTask(): Task<void, [string]> {
|
96
|
-
return useAsyncTask<void, [string]>(async (_signal, id) => {
|
97
|
-
return await API.runRule(id)
|
98
|
-
})
|
99
|
-
}
|
100
|
-
|
101
|
-
export function generateCreateRuleTask(): Task<Rule, [CreateRule]> {
|
102
|
-
return useAsyncTask<Rule, [CreateRule]>(async (_signal, payload) => {
|
103
|
-
return await API.createRule(payload)
|
104
|
-
})
|
105
|
-
}
|
106
|
-
|
107
|
-
export function generateUpdateRuleTask(): Task<Rule, [UpdateRule]> {
|
108
|
-
return useAsyncTask<Rule, [UpdateRule]>(async (_signal, payload) => {
|
109
|
-
return await API.updateRule(payload)
|
110
|
-
})
|
111
|
-
}
|
data/frontend/src/api.ts
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
import axios from "axios"
|
2
|
-
|
3
|
-
import type {
|
4
|
-
Alerts,
|
5
|
-
AlertSearchParams,
|
6
|
-
ArtifactWithTags,
|
7
|
-
Config,
|
8
|
-
CreateRule,
|
9
|
-
IPInfo,
|
10
|
-
Rule,
|
11
|
-
Rules,
|
12
|
-
RuleSearchParams,
|
13
|
-
RuleSet,
|
14
|
-
Tags,
|
15
|
-
UpdateRule
|
16
|
-
} from "@/types"
|
17
|
-
|
18
|
-
const client = axios.create({
|
19
|
-
headers: {
|
20
|
-
Accept: "application/json"
|
21
|
-
}
|
22
|
-
})
|
23
|
-
|
24
|
-
export const API = {
|
25
|
-
async getConfigs(): Promise<Config[]> {
|
26
|
-
const res = await client.get<Config[]>("/api/configs")
|
27
|
-
return res.data
|
28
|
-
},
|
29
|
-
|
30
|
-
async getAlerts(params: AlertSearchParams): Promise<Alerts> {
|
31
|
-
params.page = params.page || 1
|
32
|
-
const res = await client.get<Alerts>("/api/alerts", {
|
33
|
-
params: params
|
34
|
-
})
|
35
|
-
return res.data
|
36
|
-
},
|
37
|
-
|
38
|
-
async getTags(): Promise<string[]> {
|
39
|
-
const res = await client.get<Tags>("/api/tags")
|
40
|
-
return res.data.tags
|
41
|
-
},
|
42
|
-
|
43
|
-
async getRuleSet(): Promise<string[]> {
|
44
|
-
const res = await client.get<RuleSet>("/api/rules/ids")
|
45
|
-
return res.data.ruleIds
|
46
|
-
},
|
47
|
-
|
48
|
-
async deleteAlert(id: string): Promise<void> {
|
49
|
-
await client.delete(`/api/alerts/${id}`)
|
50
|
-
},
|
51
|
-
|
52
|
-
async getArtifact(id: string): Promise<ArtifactWithTags> {
|
53
|
-
const res = await client.get(`/api/artifacts/${id}`)
|
54
|
-
return res.data
|
55
|
-
},
|
56
|
-
|
57
|
-
async enrichArtifact(id: string): Promise<void> {
|
58
|
-
await client.get(`/api/artifacts/${id}/enrich`)
|
59
|
-
return
|
60
|
-
},
|
61
|
-
|
62
|
-
async deleteArtifact(id: string): Promise<void> {
|
63
|
-
await client.delete(`/api/artifacts/${id}`)
|
64
|
-
},
|
65
|
-
|
66
|
-
async getRules(params: RuleSearchParams): Promise<Rules> {
|
67
|
-
params.page = params.page || 1
|
68
|
-
const res = await client.get<Rules>("/api/rules", {
|
69
|
-
params: params
|
70
|
-
})
|
71
|
-
return res.data
|
72
|
-
},
|
73
|
-
|
74
|
-
async getRule(id: string): Promise<Rule> {
|
75
|
-
const res = await client.get<Rule>(`/api/rules/${id}`)
|
76
|
-
return res.data
|
77
|
-
},
|
78
|
-
|
79
|
-
async runRule(id: string): Promise<void> {
|
80
|
-
await client.get<void>(`/api/rules/${id}/run`)
|
81
|
-
},
|
82
|
-
|
83
|
-
async createRule(payload: CreateRule): Promise<Rule> {
|
84
|
-
const res = await client.post<Rule>("/api/rules/", payload)
|
85
|
-
return res.data
|
86
|
-
},
|
87
|
-
|
88
|
-
async updateRule(payload: UpdateRule): Promise<Rule> {
|
89
|
-
const res = await client.put<Rule>("/api/rules/", payload)
|
90
|
-
return res.data
|
91
|
-
},
|
92
|
-
|
93
|
-
async deleteRule(id: string): Promise<void> {
|
94
|
-
await client.delete<void>(`/api/rules/${id}`)
|
95
|
-
},
|
96
|
-
|
97
|
-
async deleteTag(name: string): Promise<void> {
|
98
|
-
await client.delete(`/api/tags/${name}`)
|
99
|
-
},
|
100
|
-
|
101
|
-
async getIPInfo(ipAddress: string): Promise<IPInfo> {
|
102
|
-
const res = await client.get<IPInfo>(`/api/ip_addresses/${ipAddress}`)
|
103
|
-
return res.data
|
104
|
-
}
|
105
|
-
}
|
@@ -1,31 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<div class="notification is-danger is-light">
|
3
|
-
<p v-if="error.response.data?.message">{{ error.response.data.message }}</p>
|
4
|
-
<p v-else>{{ error }}</p>
|
5
|
-
</div>
|
6
|
-
<article class="message" v-if="error.response.data?.details">
|
7
|
-
<div class="message-body">
|
8
|
-
<VueJsonPretty :data="error.response.data.details"></VueJsonPretty>
|
9
|
-
</div>
|
10
|
-
</article>
|
11
|
-
</template>
|
12
|
-
|
13
|
-
<script lang="ts">
|
14
|
-
import "vue-json-pretty/lib/styles.css"
|
15
|
-
|
16
|
-
import { defineComponent } from "vue"
|
17
|
-
import VueJsonPretty from "vue-json-pretty"
|
18
|
-
|
19
|
-
export default defineComponent({
|
20
|
-
name: "ErrorItem",
|
21
|
-
props: {
|
22
|
-
error: {
|
23
|
-
type: Object,
|
24
|
-
required: true
|
25
|
-
}
|
26
|
-
},
|
27
|
-
components: {
|
28
|
-
VueJsonPretty
|
29
|
-
}
|
30
|
-
})
|
31
|
-
</script>
|
@@ -1,15 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<div class="has-text-centered">
|
3
|
-
<div class="fa-3x">
|
4
|
-
<font-awesome-icon icon="spinner" spin></font-awesome-icon>
|
5
|
-
</div>
|
6
|
-
</div>
|
7
|
-
</template>
|
8
|
-
|
9
|
-
<script lang="ts">
|
10
|
-
import { defineComponent } from "vue"
|
11
|
-
|
12
|
-
export default defineComponent({
|
13
|
-
name: "LoadingItem"
|
14
|
-
})
|
15
|
-
</script>
|
@@ -1,42 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<nav role="navigation" aria-label="main navigation" class="navbar is-fixed-top">
|
3
|
-
<div class="navbar-brand">
|
4
|
-
<a class="navbar-item"><h1 class="title">Mihari</h1></a
|
5
|
-
><a role="button" aria-label="menu" class="navbar-burger burger"
|
6
|
-
><span aria-hidden="true"></span><span aria-hidden="true"></span
|
7
|
-
><span aria-hidden="true"></span
|
8
|
-
></a>
|
9
|
-
</div>
|
10
|
-
<div class="navbar-menu">
|
11
|
-
<div class="navbar-start"></div>
|
12
|
-
<div class="navbar-end">
|
13
|
-
<router-link class="navbar-item" :to="{ name: 'Alerts' }">Alerts</router-link>
|
14
|
-
<router-link class="navbar-item" :to="{ name: 'NewRule' }">New rule</router-link>
|
15
|
-
<router-link class="navbar-item" :to="{ name: 'Rules' }">Rules</router-link>
|
16
|
-
<router-link class="navbar-item" :to="{ name: 'Configs' }">Configs</router-link>
|
17
|
-
<a class="navbar-item"
|
18
|
-
><a href="/redoc-static.html" target="_blank" class="navbar-item">API</a></a
|
19
|
-
>
|
20
|
-
<a class="navbar-item"
|
21
|
-
><a href="https://github.com/ninoseki/mihari" target="_blank" class="navbar-item"
|
22
|
-
>GitHub</a
|
23
|
-
></a
|
24
|
-
>
|
25
|
-
</div>
|
26
|
-
</div>
|
27
|
-
</nav>
|
28
|
-
</template>
|
29
|
-
|
30
|
-
<script lang="ts">
|
31
|
-
import { defineComponent } from "vue"
|
32
|
-
|
33
|
-
export default defineComponent({
|
34
|
-
name: "NavbarItem"
|
35
|
-
})
|
36
|
-
</script>
|
37
|
-
|
38
|
-
<style scoped>
|
39
|
-
.navbar {
|
40
|
-
border-bottom: 1px solid lightgray;
|
41
|
-
}
|
42
|
-
</style>
|
@@ -1,119 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<article class="message is-warning" v-if="total === 0">
|
3
|
-
<div class="message-body">There is no result to show.</div>
|
4
|
-
</article>
|
5
|
-
<nav class="pagination" role="navigation" aria-label="pagination" v-else>
|
6
|
-
<ul class="pagination-list" v-if="hasOnlyOnePage">
|
7
|
-
<li>
|
8
|
-
<a class="pagination-link mt-2 is-current" @click="updatePage(1)">1</a>
|
9
|
-
</li>
|
10
|
-
</ul>
|
11
|
-
<ul class="pagination-list" v-else>
|
12
|
-
<li v-if="hasPreviousPage && isPreviousPageNotFirst">
|
13
|
-
<a class="pagination-link mt-2" @click="updatePage(1)"> 1</a>
|
14
|
-
</li>
|
15
|
-
<li v-if="hasPreviousPage && isPreviousPageNotFirst">
|
16
|
-
<span class="pagination-ellipsis">…</span>
|
17
|
-
</li>
|
18
|
-
<li v-if="hasPreviousPage">
|
19
|
-
<a class="pagination-link mt-2" @click="updatePage(currentPage - 1)">
|
20
|
-
{{ currentPage - 1 }}</a
|
21
|
-
>
|
22
|
-
</li>
|
23
|
-
<li>
|
24
|
-
<a class="pagination-link mt-2 is-current" @click="updatePage(currentPage)">
|
25
|
-
{{ currentPage }}</a
|
26
|
-
>
|
27
|
-
</li>
|
28
|
-
<li v-if="hasNextPage">
|
29
|
-
<a class="pagination-link mt-2" @click="updatePage(currentPage + 1)">
|
30
|
-
{{ currentPage + 1 }}</a
|
31
|
-
>
|
32
|
-
</li>
|
33
|
-
<li v-if="hasNextPage && isNextPageNotLast">
|
34
|
-
<span class="pagination-ellipsis">…</span>
|
35
|
-
</li>
|
36
|
-
<li v-if="hasNextPage && isNextPageNotLast">
|
37
|
-
<a class="pagination-link mt-2" @click="updatePage(totalPageCount)">{{ totalPageCount }}</a>
|
38
|
-
</li>
|
39
|
-
</ul>
|
40
|
-
</nav>
|
41
|
-
</template>
|
42
|
-
|
43
|
-
<script lang="ts">
|
44
|
-
import { useRouteQuery } from "@vueuse/router"
|
45
|
-
import { computed, defineComponent, onMounted, type Ref } from "vue"
|
46
|
-
import { useRoute, useRouter } from "vue-router"
|
47
|
-
|
48
|
-
export default defineComponent({
|
49
|
-
name: "AlertsPagination",
|
50
|
-
props: {
|
51
|
-
currentPage: {
|
52
|
-
type: Number,
|
53
|
-
required: true
|
54
|
-
},
|
55
|
-
pageSize: {
|
56
|
-
type: Number,
|
57
|
-
required: true
|
58
|
-
},
|
59
|
-
total: {
|
60
|
-
type: Number,
|
61
|
-
required: true
|
62
|
-
}
|
63
|
-
},
|
64
|
-
emits: ["update-page"],
|
65
|
-
setup(props, context) {
|
66
|
-
const route = useRoute()
|
67
|
-
const router = useRouter()
|
68
|
-
const options = { route, router }
|
69
|
-
|
70
|
-
const totalPageCount = computed(() => {
|
71
|
-
return Math.ceil(props.total / props.pageSize)
|
72
|
-
})
|
73
|
-
|
74
|
-
const hasOnlyOnePage = computed(() => {
|
75
|
-
return totalPageCount.value === 1
|
76
|
-
})
|
77
|
-
|
78
|
-
const hasPreviousPage = computed(() => {
|
79
|
-
return props.currentPage > 1
|
80
|
-
})
|
81
|
-
|
82
|
-
const isPreviousPageNotFirst = computed(() => {
|
83
|
-
return props.currentPage - 1 !== 1
|
84
|
-
})
|
85
|
-
|
86
|
-
const hasNextPage = computed(() => {
|
87
|
-
return props.currentPage < totalPageCount.value
|
88
|
-
})
|
89
|
-
|
90
|
-
const isNextPageNotLast = computed(() => {
|
91
|
-
return props.currentPage + 1 !== totalPageCount.value
|
92
|
-
})
|
93
|
-
|
94
|
-
const updatePage = (page: number) => {
|
95
|
-
const pageQuery = useRouteQuery("page", page.toString(), options)
|
96
|
-
pageQuery.value = page.toString()
|
97
|
-
|
98
|
-
context.emit("update-page", page)
|
99
|
-
}
|
100
|
-
|
101
|
-
onMounted(() => {
|
102
|
-
const pageQuery = useRouteQuery("page", null, options) as Ref<string | null>
|
103
|
-
if (pageQuery.value && parseInt(pageQuery.value) !== props.currentPage) {
|
104
|
-
updatePage(parseInt(pageQuery.value))
|
105
|
-
}
|
106
|
-
})
|
107
|
-
|
108
|
-
return {
|
109
|
-
updatePage,
|
110
|
-
hasNextPage,
|
111
|
-
hasOnlyOnePage,
|
112
|
-
hasPreviousPage,
|
113
|
-
isNextPageNotLast,
|
114
|
-
isPreviousPageNotFirst,
|
115
|
-
totalPageCount
|
116
|
-
}
|
117
|
-
}
|
118
|
-
})
|
119
|
-
</script>
|
@@ -1,87 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<div class="box">
|
3
|
-
<table class="table is-fullwidth is-completely-borderless">
|
4
|
-
<tr>
|
5
|
-
<th>ID</th>
|
6
|
-
<td>
|
7
|
-
{{ alert.id }}
|
8
|
-
<button class="button is-light is-small is-pulled-right" @click="deleteAlert">
|
9
|
-
<span>Delete</span>
|
10
|
-
<span class="icon is-small">
|
11
|
-
<font-awesome-icon icon="times"></font-awesome-icon>
|
12
|
-
</span>
|
13
|
-
</button>
|
14
|
-
</td>
|
15
|
-
</tr>
|
16
|
-
<tr>
|
17
|
-
<th>Rule</th>
|
18
|
-
<td>
|
19
|
-
<router-link :to="{ name: 'Rule', params: { id: alert.ruleId } }">{{
|
20
|
-
alert.ruleId
|
21
|
-
}}</router-link>
|
22
|
-
</td>
|
23
|
-
</tr>
|
24
|
-
<tr>
|
25
|
-
<th>Artifacts</th>
|
26
|
-
<td>
|
27
|
-
<Artifacts :artifacts="alert.artifacts"></Artifacts>
|
28
|
-
</td>
|
29
|
-
</tr>
|
30
|
-
<tr v-if="alert.tags.length > 0">
|
31
|
-
<th>Tags</th>
|
32
|
-
<td>
|
33
|
-
<Tags :tags="alert.tags" @update-tag="updateTag"></Tags>
|
34
|
-
</td>
|
35
|
-
</tr>
|
36
|
-
</table>
|
37
|
-
<p class="help">Created at: {{ alert.createdAt }}</p>
|
38
|
-
</div>
|
39
|
-
</template>
|
40
|
-
|
41
|
-
<script lang="ts">
|
42
|
-
import { defineComponent, type PropType } from "vue"
|
43
|
-
|
44
|
-
import { generateDeleteAlertTask } from "@/api-helper"
|
45
|
-
import Artifacts from "@/components/artifact/ArtifactTags.vue"
|
46
|
-
import Tags from "@/components/tag/Tags.vue"
|
47
|
-
import type { Alert } from "@/types"
|
48
|
-
import { getHumanizedRelativeTime, getLocalDatetime } from "@/utils"
|
49
|
-
|
50
|
-
export default defineComponent({
|
51
|
-
name: "AlertItem",
|
52
|
-
components: {
|
53
|
-
Artifacts,
|
54
|
-
Tags
|
55
|
-
},
|
56
|
-
props: {
|
57
|
-
alert: {
|
58
|
-
type: Object as PropType<Alert>,
|
59
|
-
required: true
|
60
|
-
}
|
61
|
-
},
|
62
|
-
setup(props, context) {
|
63
|
-
const updateTag = (tag: string) => {
|
64
|
-
context.emit("update-tag", tag)
|
65
|
-
}
|
66
|
-
|
67
|
-
const deleteAlertTask = generateDeleteAlertTask()
|
68
|
-
|
69
|
-
const deleteAlert = async () => {
|
70
|
-
const result = window.confirm(`Are you sure you want to delete ${props.alert.id}?`)
|
71
|
-
|
72
|
-
if (result) {
|
73
|
-
await deleteAlertTask.perform(props.alert.id)
|
74
|
-
// refresh the page
|
75
|
-
context.emit("refresh-page")
|
76
|
-
}
|
77
|
-
}
|
78
|
-
|
79
|
-
return {
|
80
|
-
updateTag,
|
81
|
-
deleteAlert,
|
82
|
-
getLocalDatetime,
|
83
|
-
getHumanizedRelativeTime
|
84
|
-
}
|
85
|
-
}
|
86
|
-
})
|
87
|
-
</script>
|