mihari 5.7.0 → 5.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/lib/mihari/actor.rb +10 -4
  4. data/lib/mihari/commands/alert.rb +6 -4
  5. data/lib/mihari/commands/search.rb +10 -29
  6. data/lib/mihari/enrichers/ipinfo.rb +1 -1
  7. data/lib/mihari/entities/tag.rb +1 -0
  8. data/lib/mihari/rule.rb +14 -0
  9. data/lib/mihari/service.rb +12 -2
  10. data/lib/mihari/services/alert_builder.rb +81 -8
  11. data/lib/mihari/services/alert_runner.rb +3 -10
  12. data/lib/mihari/services/rule_builder.rb +8 -10
  13. data/lib/mihari/services/rule_runner.rb +2 -25
  14. data/lib/mihari/structs/binaryedge.rb +9 -0
  15. data/lib/mihari/structs/censys.rb +0 -14
  16. data/lib/mihari/structs/fofa.rb +3 -0
  17. data/lib/mihari/structs/google_public_dns.rb +0 -4
  18. data/lib/mihari/structs/greynoise.rb +0 -6
  19. data/lib/mihari/structs/hunterhow.rb +0 -6
  20. data/lib/mihari/structs/ipinfo.rb +0 -2
  21. data/lib/mihari/structs/onyphe.rb +0 -4
  22. data/lib/mihari/structs/shodan.rb +0 -2
  23. data/lib/mihari/structs/urlscan.rb +0 -6
  24. data/lib/mihari/structs/virustotal_intelligence.rb +0 -8
  25. data/lib/mihari/version.rb +1 -1
  26. data/lib/mihari/web/app.rb +20 -17
  27. data/lib/mihari/web/endpoints/alerts.rb +75 -38
  28. data/lib/mihari/web/endpoints/artifacts.rb +60 -53
  29. data/lib/mihari/web/endpoints/ip_addresses.rb +19 -4
  30. data/lib/mihari/web/endpoints/rules.rb +132 -88
  31. data/lib/mihari/web/endpoints/tags.rb +15 -13
  32. data/lib/mihari/web/public/assets/{index-821134e2.js → index-07fafab5.js} +4 -3
  33. data/lib/mihari/web/public/index.html +1 -1
  34. data/lib/mihari.rb +0 -1
  35. data/mihari.gemspec +1 -1
  36. data/mkdocs.yml +1 -0
  37. metadata +3 -130
  38. data/docs/alternatives.md +0 -5
  39. data/docs/analyzers/binaryedge.md +0 -26
  40. data/docs/analyzers/censys.md +0 -31
  41. data/docs/analyzers/circl.md +0 -37
  42. data/docs/analyzers/crtsh.md +0 -26
  43. data/docs/analyzers/dnstwister.md +0 -25
  44. data/docs/analyzers/feed.md +0 -73
  45. data/docs/analyzers/fofa.md +0 -31
  46. data/docs/analyzers/greynoise.md +0 -26
  47. data/docs/analyzers/hunterhow.md +0 -33
  48. data/docs/analyzers/index.md +0 -104
  49. data/docs/analyzers/onyphe.md +0 -26
  50. data/docs/analyzers/otx.md +0 -28
  51. data/docs/analyzers/passivetotal.md +0 -52
  52. data/docs/analyzers/pulsedive.md +0 -28
  53. data/docs/analyzers/securitytrails.md +0 -41
  54. data/docs/analyzers/shodan.md +0 -26
  55. data/docs/analyzers/urlscan.md +0 -28
  56. data/docs/analyzers/virustotal.md +0 -43
  57. data/docs/analyzers/virustotal_intelligence.md +0 -33
  58. data/docs/analyzers/zoomeye.md +0 -38
  59. data/docs/configuration.md +0 -35
  60. data/docs/emitters/database.md +0 -22
  61. data/docs/emitters/hive.md +0 -26
  62. data/docs/emitters/index.md +0 -36
  63. data/docs/emitters/misp.md +0 -21
  64. data/docs/emitters/slack.md +0 -21
  65. data/docs/emitters/webhook.md +0 -63
  66. data/docs/enrichers/google_public_dns.md +0 -19
  67. data/docs/enrichers/index.md +0 -35
  68. data/docs/enrichers/ipinfo.md +0 -26
  69. data/docs/enrichers/shodan.md +0 -22
  70. data/docs/enrichers/whois.md +0 -17
  71. data/docs/github_actions.md +0 -43
  72. data/docs/index.md +0 -11
  73. data/docs/installation.md +0 -31
  74. data/docs/requirements.md +0 -13
  75. data/docs/rule.md +0 -168
  76. data/docs/tags.md +0 -3
  77. data/docs/usage.md +0 -103
  78. data/frontend/.eslintrc.cjs +0 -22
  79. data/frontend/.gitignore +0 -31
  80. data/frontend/.prettierrc.json +0 -8
  81. data/frontend/README.md +0 -3
  82. data/frontend/env.d.ts +0 -5
  83. data/frontend/index.html +0 -21
  84. data/frontend/package-lock.json +0 -7219
  85. data/frontend/package.json +0 -67
  86. data/frontend/public/favicon.ico +0 -0
  87. data/frontend/scripts/swagger_doc_to_yaml.rb +0 -23
  88. data/frontend/src/App.vue +0 -27
  89. data/frontend/src/ace-config.ts +0 -6
  90. data/frontend/src/api-helper.ts +0 -111
  91. data/frontend/src/api.ts +0 -105
  92. data/frontend/src/components/ErrorMessage.vue +0 -31
  93. data/frontend/src/components/Loading.vue +0 -15
  94. data/frontend/src/components/Navbar.vue +0 -42
  95. data/frontend/src/components/Pagination.vue +0 -119
  96. data/frontend/src/components/alert/Alert.vue +0 -87
  97. data/frontend/src/components/alert/Alerts.vue +0 -63
  98. data/frontend/src/components/alert/AlertsWithPagination.vue +0 -90
  99. data/frontend/src/components/alert/AlertsWrapper.vue +0 -128
  100. data/frontend/src/components/alert/Form.vue +0 -169
  101. data/frontend/src/components/artifact/AS.vue +0 -23
  102. data/frontend/src/components/artifact/Artifact.vue +0 -287
  103. data/frontend/src/components/artifact/ArtifactTag.vue +0 -64
  104. data/frontend/src/components/artifact/ArtifactTags.vue +0 -29
  105. data/frontend/src/components/artifact/ArtifactWrapper.vue +0 -57
  106. data/frontend/src/components/artifact/CPEs.vue +0 -23
  107. data/frontend/src/components/artifact/DnsRecords.vue +0 -32
  108. data/frontend/src/components/artifact/Ports.vue +0 -23
  109. data/frontend/src/components/artifact/ReverseDnsNames.vue +0 -23
  110. data/frontend/src/components/artifact/Tags.vue +0 -29
  111. data/frontend/src/components/artifact/WhoisRecord.vue +0 -44
  112. data/frontend/src/components/config/Configs.vue +0 -65
  113. data/frontend/src/components/config/ConfigsWrapper.vue +0 -32
  114. data/frontend/src/components/link/Link.vue +0 -32
  115. data/frontend/src/components/link/Links.vue +0 -42
  116. data/frontend/src/components/rule/EditRule.vue +0 -72
  117. data/frontend/src/components/rule/EditRuleWrapper.vue +0 -48
  118. data/frontend/src/components/rule/Form.vue +0 -158
  119. data/frontend/src/components/rule/InputForm.vue +0 -45
  120. data/frontend/src/components/rule/NewRule.vue +0 -57
  121. data/frontend/src/components/rule/Rule.vue +0 -100
  122. data/frontend/src/components/rule/RuleWrapper.vue +0 -53
  123. data/frontend/src/components/rule/Rules.vue +0 -84
  124. data/frontend/src/components/rule/RulesWrapper.vue +0 -121
  125. data/frontend/src/components/rule/YAML.vue +0 -37
  126. data/frontend/src/components/tag/Tag.vue +0 -65
  127. data/frontend/src/components/tag/Tags.vue +0 -37
  128. data/frontend/src/countries.ts +0 -350
  129. data/frontend/src/index.ts +0 -20
  130. data/frontend/src/links/anyrun.ts +0 -19
  131. data/frontend/src/links/base.ts +0 -14
  132. data/frontend/src/links/censys.ts +0 -20
  133. data/frontend/src/links/crtsh.ts +0 -20
  134. data/frontend/src/links/dnslytics.ts +0 -38
  135. data/frontend/src/links/greynoise.ts +0 -20
  136. data/frontend/src/links/index.ts +0 -40
  137. data/frontend/src/links/intezer.ts +0 -20
  138. data/frontend/src/links/otx.ts +0 -33
  139. data/frontend/src/links/securitytrails.ts +0 -38
  140. data/frontend/src/links/shodan.ts +0 -20
  141. data/frontend/src/links/urlscan.ts +0 -50
  142. data/frontend/src/links/virustotal.ts +0 -72
  143. data/frontend/src/main.ts +0 -41
  144. data/frontend/src/router/index.ts +0 -57
  145. data/frontend/src/rule.ts +0 -14
  146. data/frontend/src/shims-vue.d.ts +0 -6
  147. data/frontend/src/swagger.yaml +0 -771
  148. data/frontend/src/types.ts +0 -188
  149. data/frontend/src/utils.ts +0 -54
  150. data/frontend/src/views/Alerts.vue +0 -20
  151. data/frontend/src/views/Artifact.vue +0 -39
  152. data/frontend/src/views/Configs.vue +0 -20
  153. data/frontend/src/views/EditRule.vue +0 -39
  154. data/frontend/src/views/NewRule.vue +0 -26
  155. data/frontend/src/views/Rule.vue +0 -39
  156. data/frontend/src/views/Rules.vue +0 -20
  157. data/frontend/tests/utils.spec.ts +0 -9
  158. data/frontend/tsconfig.app.json +0 -21
  159. data/frontend/tsconfig.json +0 -14
  160. data/frontend/tsconfig.node.json +0 -13
  161. data/frontend/tsconfig.vitest.json +0 -12
  162. data/frontend/vite.config.ts +0 -24
  163. data/frontend/vitest.config.ts +0 -21
  164. data/lib/mihari/services/alert_proxy.rb +0 -97
@@ -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
- }
@@ -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>
@@ -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
- })
@@ -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
- }
@@ -1,14 +0,0 @@
1
- {
2
- "files": [],
3
- "references": [
4
- {
5
- "path": "./tsconfig.node.json"
6
- },
7
- {
8
- "path": "./tsconfig.app.json"
9
- },
10
- {
11
- "path": "./tsconfig.vitest.json"
12
- }
13
- ]
14
- }
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "@tsconfig/node20/tsconfig.json",
3
- "include": [
4
- "vite.config.*",
5
- ],
6
- "compilerOptions": {
7
- "composite": true,
8
- "module": "ESNext",
9
- "types": [
10
- "node"
11
- ]
12
- }
13
- }
@@ -1,12 +0,0 @@
1
- {
2
- "extends": "./tsconfig.app.json",
3
- "exclude": [],
4
- "compilerOptions": {
5
- "composite": true,
6
- "lib": [],
7
- "types": [
8
- "node",
9
- "jsdom"
10
- ]
11
- }
12
- }
@@ -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
- })
@@ -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,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