mihari 5.2.4 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/README.md +0 -10
  4. data/Rakefile +7 -1
  5. data/build_frontend.sh +1 -1
  6. data/frontend/.eslintrc.cjs +22 -0
  7. data/frontend/.gitignore +18 -12
  8. data/frontend/.prettierrc.json +8 -0
  9. data/frontend/env.d.ts +5 -0
  10. data/frontend/package-lock.json +5095 -9661
  11. data/frontend/package.json +34 -24
  12. data/frontend/src/App.vue +5 -5
  13. data/frontend/src/api-helper.ts +38 -40
  14. data/frontend/src/api.ts +40 -40
  15. data/frontend/src/components/ErrorMessage.vue +8 -8
  16. data/frontend/src/components/Loading.vue +3 -3
  17. data/frontend/src/components/Navbar.vue +10 -27
  18. data/frontend/src/components/Pagination.vue +35 -42
  19. data/frontend/src/components/alert/Alert.vue +21 -26
  20. data/frontend/src/components/alert/Alerts.vue +23 -25
  21. data/frontend/src/components/alert/AlertsWithPagination.vue +34 -34
  22. data/frontend/src/components/alert/AlertsWrapper.vue +42 -49
  23. data/frontend/src/components/alert/Form.vue +39 -40
  24. data/frontend/src/components/artifact/AS.vue +7 -7
  25. data/frontend/src/components/artifact/Artifact.vue +66 -83
  26. data/frontend/src/components/artifact/ArtifactTag.vue +21 -27
  27. data/frontend/src/components/artifact/ArtifactTags.vue +8 -8
  28. data/frontend/src/components/artifact/ArtifactWrapper.vue +22 -25
  29. data/frontend/src/components/artifact/CPEs.vue +6 -6
  30. data/frontend/src/components/artifact/DnsRecords.vue +9 -9
  31. data/frontend/src/components/artifact/Ports.vue +6 -6
  32. data/frontend/src/components/artifact/ReverseDnsNames.vue +7 -7
  33. data/frontend/src/components/artifact/Tags.vue +6 -6
  34. data/frontend/src/components/artifact/WhoisRecord.vue +7 -9
  35. data/frontend/src/components/config/Configs.vue +7 -10
  36. data/frontend/src/components/config/ConfigsWrapper.vue +14 -20
  37. data/frontend/src/components/link/Link.vue +7 -7
  38. data/frontend/src/components/link/Links.vue +16 -21
  39. data/frontend/src/components/rule/EditRule.vue +22 -22
  40. data/frontend/src/components/rule/EditRuleWrapper.vue +22 -28
  41. data/frontend/src/components/rule/Form.vue +28 -28
  42. data/frontend/src/components/rule/InputForm.vue +31 -25
  43. data/frontend/src/components/rule/NewRule.vue +18 -18
  44. data/frontend/src/components/rule/Rule.vue +25 -27
  45. data/frontend/src/components/rule/RuleWrapper.vue +24 -31
  46. data/frontend/src/components/rule/Rules.vue +26 -30
  47. data/frontend/src/components/rule/RulesWrapper.vue +39 -42
  48. data/frontend/src/components/rule/YAML.vue +19 -22
  49. data/frontend/src/components/tag/Tag.vue +24 -32
  50. data/frontend/src/components/tag/Tags.vue +11 -11
  51. data/frontend/src/countries.ts +23 -23
  52. data/frontend/src/index.ts +9 -12
  53. data/frontend/src/links/anyrun.ts +10 -10
  54. data/frontend/src/links/base.ts +3 -3
  55. data/frontend/src/links/censys.ts +10 -10
  56. data/frontend/src/links/crtsh.ts +10 -10
  57. data/frontend/src/links/dnslytics.ts +18 -18
  58. data/frontend/src/links/greynoise.ts +10 -10
  59. data/frontend/src/links/index.ts +15 -15
  60. data/frontend/src/links/intezer.ts +10 -10
  61. data/frontend/src/links/otx.ts +14 -14
  62. data/frontend/src/links/securitytrails.ts +15 -15
  63. data/frontend/src/links/shodan.ts +10 -10
  64. data/frontend/src/links/urlscan.ts +19 -19
  65. data/frontend/src/links/virustotal.ts +27 -27
  66. data/frontend/src/main.ts +8 -8
  67. data/frontend/src/router/index.ts +20 -20
  68. data/frontend/src/rule.ts +6 -6
  69. data/frontend/src/shims-vue.d.ts +2 -2
  70. data/frontend/src/types.ts +91 -91
  71. data/frontend/src/utils.ts +23 -29
  72. data/frontend/src/views/Alerts.vue +7 -7
  73. data/frontend/src/views/Artifact.vue +17 -17
  74. data/frontend/src/views/Configs.vue +7 -7
  75. data/frontend/src/views/EditRule.vue +17 -17
  76. data/frontend/src/views/NewRule.vue +10 -10
  77. data/frontend/src/views/Rule.vue +17 -17
  78. data/frontend/src/views/Rules.vue +7 -7
  79. data/frontend/tests/utils.spec.ts +9 -0
  80. data/frontend/tsconfig.app.json +21 -0
  81. data/frontend/tsconfig.json +10 -36
  82. data/frontend/tsconfig.node.json +13 -0
  83. data/frontend/tsconfig.vitest.json +12 -0
  84. data/frontend/vite.config.ts +24 -0
  85. data/frontend/vitest.config.ts +21 -0
  86. data/lefthook.yml +4 -2
  87. data/lib/mihari/analyzers/base.rb +48 -14
  88. data/lib/mihari/analyzers/binaryedge.rb +10 -15
  89. data/lib/mihari/analyzers/censys.rb +12 -15
  90. data/lib/mihari/analyzers/circl.rb +10 -10
  91. data/lib/mihari/analyzers/crtsh.rb +10 -6
  92. data/lib/mihari/analyzers/dnstwister.rb +6 -8
  93. data/lib/mihari/analyzers/feed.rb +21 -10
  94. data/lib/mihari/analyzers/greynoise.rb +10 -20
  95. data/lib/mihari/analyzers/onyphe.rb +9 -14
  96. data/lib/mihari/analyzers/otx.rb +8 -9
  97. data/lib/mihari/analyzers/passivetotal.rb +10 -10
  98. data/lib/mihari/analyzers/pulsedive.rb +21 -31
  99. data/lib/mihari/analyzers/securitytrails.rb +8 -6
  100. data/lib/mihari/analyzers/shodan.rb +8 -13
  101. data/lib/mihari/analyzers/urlscan.rb +15 -20
  102. data/lib/mihari/analyzers/virustotal.rb +16 -26
  103. data/lib/mihari/analyzers/virustotal_intelligence.rb +11 -17
  104. data/lib/mihari/analyzers/zoomeye.rb +12 -17
  105. data/lib/mihari/config.rb +133 -0
  106. data/lib/mihari/constants.rb +3 -0
  107. data/lib/mihari/emitters/slack.rb +13 -3
  108. data/lib/mihari/errors.rb +1 -1
  109. data/lib/mihari/http.rb +2 -3
  110. data/lib/mihari/schemas/analyzer.rb +2 -0
  111. data/lib/mihari/type_checker.rb +6 -6
  112. data/lib/mihari/version.rb +1 -1
  113. data/lib/mihari/web/endpoints/configs.rb +5 -1
  114. data/lib/mihari/web/public/assets/{index-eed1bcd8.css → index-2ba8f0a6.css} +1 -1
  115. data/lib/mihari/web/public/assets/{index-ac4e5ffa.js → index-71285b15.js} +16 -16
  116. data/lib/mihari/web/public/index.html +2 -2
  117. data/lib/mihari/web/public/redoc-static.html +388 -2193
  118. data/lib/mihari.rb +9 -59
  119. data/mihari.gemspec +8 -8
  120. metadata +24 -62
  121. data/frontend/.browserslistrc +0 -3
  122. data/frontend/.eslintrc.js +0 -33
  123. data/frontend/babel.config.js +0 -3
  124. data/frontend/jest.config.js +0 -9
  125. data/frontend/tests/unit/utils.spec.ts +0 -7
  126. data/frontend/vite.config.js +0 -24
@@ -1,62 +1,55 @@
1
1
  <template>
2
2
  <Loading v-if="getRuleTask.isRunning"></Loading>
3
3
 
4
- <ErrorMessage
5
- v-if="getRuleTask.isError"
6
- :error="getRuleTask.last?.error"
7
- ></ErrorMessage>
8
-
9
- <Rule
10
- :rule="getRuleTask.last.value"
11
- @refresh="refresh"
12
- v-if="getRuleTask.last?.value"
13
- ></Rule>
4
+ <ErrorMessage v-if="getRuleTask.isError" :error="getRuleTask.last?.error"></ErrorMessage>
5
+
6
+ <Rule :rule="getRuleTask.last.value" @refresh="refresh" v-if="getRuleTask.last?.value"></Rule>
14
7
  </template>
15
8
 
16
9
  <script lang="ts">
17
- import { defineComponent, onMounted, watch } from "vue";
10
+ import { defineComponent, onMounted, watch } from "vue"
18
11
 
19
- import { generateGetRuleTask } from "@/api-helper";
20
- import ErrorMessage from "@/components/ErrorMessage.vue";
21
- import Loading from "@/components/Loading.vue";
22
- import Rule from "@/components/rule/Rule.vue";
12
+ import { generateGetRuleTask } from "@/api-helper"
13
+ import ErrorMessage from "@/components/ErrorMessage.vue"
14
+ import Loading from "@/components/Loading.vue"
15
+ import Rule from "@/components/rule/Rule.vue"
23
16
 
24
17
  export default defineComponent({
25
18
  name: "RuleWrapper",
26
19
  components: {
27
20
  Rule,
28
21
  Loading,
29
- ErrorMessage,
22
+ ErrorMessage
30
23
  },
31
24
  props: {
32
25
  id: {
33
26
  type: String,
34
- required: true,
35
- },
27
+ required: true
28
+ }
36
29
  },
37
30
  setup(props) {
38
- const getRuleTask = generateGetRuleTask();
31
+ const getRuleTask = generateGetRuleTask()
39
32
 
40
33
  const getRule = async () => {
41
- await getRuleTask.perform(props.id);
42
- };
34
+ await getRuleTask.perform(props.id)
35
+ }
43
36
 
44
37
  const refresh = async () => {
45
- await getRule();
46
- };
38
+ await getRule()
39
+ }
47
40
 
48
41
  onMounted(async () => {
49
- await getRule();
50
- });
42
+ await getRule()
43
+ })
51
44
 
52
45
  watch(props, async () => {
53
- await getRule();
54
- });
46
+ await getRule()
47
+ })
55
48
 
56
49
  return {
57
50
  getRuleTask,
58
- refresh,
59
- };
60
- },
61
- });
51
+ refresh
52
+ }
53
+ }
54
+ })
62
55
  </script>
@@ -9,9 +9,7 @@
9
9
  </tr>
10
10
  <tr v-for="rule in rules.rules" :key="rule.id">
11
11
  <td>
12
- <router-link :to="{ name: 'Rule', params: { id: rule.id } }">{{
13
- rule.id
14
- }}</router-link>
12
+ <router-link :to="{ name: 'Rule', params: { id: rule.id } }">{{ rule.id }}</router-link>
15
13
  </td>
16
14
  <td>
17
15
  {{ rule.title }}
@@ -31,58 +29,56 @@
31
29
  :pageSize="rules.pageSize"
32
30
  @update-page="updatePage"
33
31
  ></Pagination>
34
- <p class="help">
35
- ({{ rules.total }} results in total, {{ rules.rules.length }} shown)
36
- </p>
32
+ <p class="help">({{ rules.total }} results in total, {{ rules.rules.length }} shown)</p>
37
33
  </template>
38
34
 
39
35
  <script lang="ts">
40
- import { computed, defineComponent, PropType } from "vue";
36
+ import { computed, defineComponent, type PropType } from "vue"
41
37
 
42
- import Pagination from "@/components/Pagination.vue";
43
- import Tags from "@/components/tag/Tags.vue";
44
- import { Rules } from "@/types";
38
+ import Pagination from "@/components/Pagination.vue"
39
+ import Tags from "@/components/tag/Tags.vue"
40
+ import type { Rules } from "@/types"
45
41
 
46
42
  export default defineComponent({
47
43
  name: "RulesItem",
48
44
  props: {
49
45
  rules: {
50
46
  type: Object as PropType<Rules>,
51
- required: true,
52
- },
47
+ required: true
48
+ }
53
49
  },
54
50
  components: {
55
51
  Pagination,
56
- Tags,
52
+ Tags
57
53
  },
58
54
  emits: ["update-page", "refresh-page", "update-tag"],
59
55
  setup(props, context) {
60
56
  const scrollToTop = () => {
61
57
  window.scrollTo({
62
- top: 0,
63
- });
64
- };
58
+ top: 0
59
+ })
60
+ }
65
61
 
66
62
  const updatePage = (page: number) => {
67
- scrollToTop();
68
- context.emit("update-page", page);
69
- };
63
+ scrollToTop()
64
+ context.emit("update-page", page)
65
+ }
70
66
 
71
67
  const refreshPage = () => {
72
- scrollToTop();
73
- context.emit("refresh-page");
74
- };
68
+ scrollToTop()
69
+ context.emit("refresh-page")
70
+ }
75
71
 
76
72
  const updateTag = (tag: string) => {
77
- scrollToTop();
78
- context.emit("update-tag", tag);
79
- };
73
+ scrollToTop()
74
+ context.emit("update-tag", tag)
75
+ }
80
76
 
81
77
  const hasRules = computed(() => {
82
- return props.rules.rules.length > 0;
83
- });
78
+ return props.rules.rules.length > 0
79
+ })
84
80
 
85
- return { updatePage, refreshPage, updateTag, hasRules };
86
- },
87
- });
81
+ return { updatePage, refreshPage, updateTag, hasRules }
82
+ }
83
+ })
88
84
  </script>
@@ -28,10 +28,7 @@
28
28
 
29
29
  <Loading v-if="getRulesTask.isRunning"></Loading>
30
30
 
31
- <ErrorMessage
32
- v-if="getRulesTask.isError"
33
- :error="getRulesTask.last?.error"
34
- ></ErrorMessage>
31
+ <ErrorMessage v-if="getRulesTask.isError" :error="getRulesTask.last?.error"></ErrorMessage>
35
32
 
36
33
  <Rules
37
34
  :rules="getRulesTask.last.value"
@@ -44,14 +41,14 @@
44
41
  </template>
45
42
 
46
43
  <script lang="ts">
47
- import { defineComponent, nextTick, onMounted, ref, watch } from "vue";
44
+ import { defineComponent, nextTick, onMounted, ref, watch } from "vue"
48
45
 
49
- import { generateGetRulesTask, generateGetTagsTask } from "@/api-helper";
50
- import ErrorMessage from "@/components/ErrorMessage.vue";
51
- import Loading from "@/components/Loading.vue";
52
- import FormComponent from "@/components/rule/Form.vue";
53
- import Rules from "@/components/rule/Rules.vue";
54
- import { RuleSearchParams } from "@/types";
46
+ import { generateGetRulesTask, generateGetTagsTask } from "@/api-helper"
47
+ import ErrorMessage from "@/components/ErrorMessage.vue"
48
+ import Loading from "@/components/Loading.vue"
49
+ import FormComponent from "@/components/rule/Form.vue"
50
+ import Rules from "@/components/rule/Rules.vue"
51
+ import type { RuleSearchParams } from "@/types"
55
52
 
56
53
  export default defineComponent({
57
54
  name: "RulesWrapper",
@@ -59,60 +56,60 @@ export default defineComponent({
59
56
  Rules,
60
57
  Loading,
61
58
  FormComponent,
62
- ErrorMessage,
59
+ ErrorMessage
63
60
  },
64
61
  setup() {
65
- const page = ref(1);
66
- const tag = ref<string | undefined>(undefined);
67
- const form = ref<InstanceType<typeof FormComponent>>();
62
+ const page = ref(1)
63
+ const tag = ref<string | undefined>(undefined)
64
+ const form = ref<InstanceType<typeof FormComponent>>()
68
65
 
69
- const getRulesTask = generateGetRulesTask();
70
- const getTagsTask = generateGetTagsTask();
66
+ const getRulesTask = generateGetRulesTask()
67
+ const getTagsTask = generateGetTagsTask()
71
68
 
72
69
  const getRules = async () => {
73
- const params = form.value?.getSearchParams() as RuleSearchParams;
74
- return await getRulesTask.perform(params);
75
- };
70
+ const params = form.value?.getSearchParams() as RuleSearchParams
71
+ return await getRulesTask.perform(params)
72
+ }
76
73
 
77
74
  const updatePage = (newPage: number) => {
78
- page.value = newPage;
79
- };
75
+ page.value = newPage
76
+ }
80
77
 
81
78
  const resetPage = () => {
82
- page.value = 1;
83
- };
79
+ page.value = 1
80
+ }
84
81
 
85
82
  const search = async () => {
86
83
  // reset page
87
- resetPage();
84
+ resetPage()
88
85
 
89
- await getRules();
90
- };
86
+ await getRules()
87
+ }
91
88
 
92
89
  const updateTag = (newTag: string | undefined) => {
93
90
  if (tag.value === newTag) {
94
- tag.value = undefined;
91
+ tag.value = undefined
95
92
  } else {
96
- tag.value = newTag;
93
+ tag.value = newTag
97
94
  }
98
95
 
99
- nextTick(async () => await search());
100
- };
96
+ nextTick(async () => await search())
97
+ }
101
98
 
102
99
  const refreshPage = async () => {
103
100
  // it is just an alias of search
104
101
  // this function will be invoked when a rule is deleted
105
- await search();
106
- };
102
+ await search()
103
+ }
107
104
 
108
105
  onMounted(async () => {
109
- getTagsTask.perform();
110
- await getRules();
111
- });
106
+ getTagsTask.perform()
107
+ await getRules()
108
+ })
112
109
 
113
110
  watch([page, tag], async () => {
114
- nextTick(async () => await getRules());
115
- });
111
+ nextTick(async () => await getRules())
112
+ })
116
113
 
117
114
  return {
118
115
  form,
@@ -123,8 +120,8 @@ export default defineComponent({
123
120
  refreshPage,
124
121
  search,
125
122
  updatePage,
126
- updateTag,
127
- };
128
- },
129
- });
123
+ updateTag
124
+ }
125
+ }
126
+ })
130
127
  </script>
@@ -1,47 +1,44 @@
1
1
  <template>
2
- <pre
3
- ref="pre"
4
- class="line-numbers"
5
- ><code class="language-yaml">{{ yaml }}</code></pre>
2
+ <pre ref="pre" class="line-numbers"><code class="language-yaml">{{ yaml }}</code></pre>
6
3
  </template>
7
4
 
8
5
  <script lang="ts">
9
6
  // eslint-disable-next-line simple-import-sort/imports
10
- import { defineComponent, onMounted, ref } from "vue";
7
+ import { defineComponent, onMounted, ref } from "vue"
11
8
 
12
- import Prism from "prismjs";
9
+ import Prism from "prismjs"
13
10
 
14
- import "prismjs/components/prism-yaml";
15
- import "prismjs/plugins/custom-class/prism-custom-class";
16
- import "prismjs/plugins/line-numbers/prism-line-numbers.css";
17
- import "prismjs/plugins/line-numbers/prism-line-numbers";
18
- import "prismjs/themes/prism-twilight.css";
11
+ import "prismjs/components/prism-yaml"
12
+ import "prismjs/plugins/custom-class/prism-custom-class"
13
+ import "prismjs/plugins/line-numbers/prism-line-numbers.css"
14
+ import "prismjs/plugins/line-numbers/prism-line-numbers"
15
+ import "prismjs/themes/prism-twilight.css"
19
16
 
20
17
  export default defineComponent({
21
18
  name: "YAML",
22
19
  props: {
23
20
  yaml: {
24
21
  type: String,
25
- required: true,
26
- },
22
+ required: true
23
+ }
27
24
  },
28
25
  setup() {
29
- const pre = ref<HTMLElement | undefined>(undefined);
26
+ const pre = ref<HTMLElement | undefined>(undefined)
30
27
 
31
28
  Prism.plugins.customClass.map({
32
29
  number: "prism-number",
33
- tag: "prism-tag",
34
- });
30
+ tag: "prism-tag"
31
+ })
35
32
 
36
33
  onMounted(() => {
37
34
  if (pre.value) {
38
35
  pre.value.querySelectorAll("code").forEach((elem) => {
39
- Prism.highlightElement(elem);
40
- });
36
+ Prism.highlightElement(elem)
37
+ })
41
38
  }
42
- });
39
+ })
43
40
 
44
- return { pre };
45
- },
46
- });
41
+ return { pre }
42
+ }
43
+ })
47
44
  </script>
@@ -5,60 +5,52 @@
5
5
  v-on:mouseover="showDeleteButton"
6
6
  v-on:mouseleave="hideDeleteButton"
7
7
  >
8
- <span class="tag is-info is-light" @click="updateTag">{{
9
- tag.name
10
- }}</span>
11
- <a
12
- class="tag is-delete"
13
- v-if="isDeleteButtonEnabled"
14
- @click="deleteTag"
15
- ></a>
8
+ <span class="tag is-info is-light" @click="updateTag">{{ tag.name }}</span>
9
+ <a class="tag is-delete" v-if="isDeleteButtonEnabled" @click="deleteTag"></a>
16
10
  </div>
17
11
  </div>
18
12
  </template>
19
13
 
20
14
  <script lang="ts">
21
- import { defineComponent, PropType, ref } from "vue";
15
+ import { defineComponent, type PropType, ref } from "vue"
22
16
 
23
- import { generateDeleteTagTask } from "@/api-helper";
24
- import { Tag } from "@/types";
17
+ import { generateDeleteTagTask } from "@/api-helper"
18
+ import type { Tag } from "@/types"
25
19
 
26
20
  export default defineComponent({
27
21
  name: "TagItem",
28
22
  props: {
29
23
  tag: {
30
24
  type: Object as PropType<Tag>,
31
- required: true,
32
- },
25
+ required: true
26
+ }
33
27
  },
34
28
  setup(props, context) {
35
- const isDeleted = ref(false);
36
- const isDeleteButtonEnabled = ref(false);
29
+ const isDeleted = ref(false)
30
+ const isDeleteButtonEnabled = ref(false)
37
31
 
38
- const deleteTagTask = generateDeleteTagTask();
32
+ const deleteTagTask = generateDeleteTagTask()
39
33
 
40
34
  const deleteTag = async () => {
41
- const result = window.confirm(
42
- `Are you sure you want to delete ${props.tag.name}?`
43
- );
35
+ const result = window.confirm(`Are you sure you want to delete ${props.tag.name}?`)
44
36
 
45
37
  if (result) {
46
- await deleteTagTask.perform(props.tag.name);
47
- isDeleted.value = true;
38
+ await deleteTagTask.perform(props.tag.name)
39
+ isDeleted.value = true
48
40
  }
49
- };
41
+ }
50
42
 
51
43
  const showDeleteButton = () => {
52
- isDeleteButtonEnabled.value = true;
53
- };
44
+ isDeleteButtonEnabled.value = true
45
+ }
54
46
 
55
47
  const hideDeleteButton = () => {
56
- isDeleteButtonEnabled.value = false;
57
- };
48
+ isDeleteButtonEnabled.value = false
49
+ }
58
50
 
59
51
  const updateTag = () => {
60
- context.emit("update-tag", props.tag.name);
61
- };
52
+ context.emit("update-tag", props.tag.name)
53
+ }
62
54
 
63
55
  return {
64
56
  updateTag,
@@ -66,8 +58,8 @@ export default defineComponent({
66
58
  deleteTag,
67
59
  showDeleteButton,
68
60
  hideDeleteButton,
69
- isDeleteButtonEnabled,
70
- };
71
- },
72
- });
61
+ isDeleteButtonEnabled
62
+ }
63
+ }
64
+ })
73
65
  </script>
@@ -10,28 +10,28 @@
10
10
  </template>
11
11
 
12
12
  <script lang="ts">
13
- import { defineComponent, PropType } from "vue";
13
+ import { defineComponent, type PropType } from "vue"
14
14
 
15
- import TagComponent from "@/components/tag/Tag.vue";
16
- import { Tag } from "@/types";
15
+ import TagComponent from "@/components/tag/Tag.vue"
16
+ import type { Tag } from "@/types"
17
17
 
18
18
  export default defineComponent({
19
19
  name: "TagsItem",
20
20
  components: {
21
- TagComponent,
21
+ TagComponent
22
22
  },
23
23
  props: {
24
24
  tags: {
25
25
  type: Array as PropType<Tag[]>,
26
- required: true,
27
- },
26
+ required: true
27
+ }
28
28
  },
29
29
  setup(_, context) {
30
30
  const updateTag = (tag: string) => {
31
- context.emit("update-tag", tag);
32
- };
31
+ context.emit("update-tag", tag)
32
+ }
33
33
 
34
- return { updateTag };
35
- },
36
- });
34
+ return { updateTag }
35
+ }
36
+ })
37
37
  </script>