mihari 5.2.4 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
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>