diff --git a/index.html b/index.html index a957ee9..8890383 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - + ThreatSlayer diff --git a/package-lock.json b/package-lock.json index 8e82994..c3a9875 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "core-js": "^3.8.3", "debounce": "^1.2.1", "openpgp": "^5.9.0", - "vue": "^3.2.13" + "vue": "^3.2.13", + "vue-plugin-webextension-i18n": "^0.1.3" }, "devDependencies": { "@babel/core": "^7.12.16", @@ -22,7 +23,7 @@ "eslint": "^7.32.0", "eslint-plugin-vue": "^8.0.3", "msw": "^1.2.1", - "vite": "^4.3.9" + "vite": "^4.4.9" } }, "node_modules/@ampproject/remapping": { @@ -342,9 +343,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -358,9 +359,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -374,9 +375,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -390,9 +391,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -406,9 +407,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -422,9 +423,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -438,9 +439,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -454,9 +455,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -470,9 +471,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -486,9 +487,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -502,9 +503,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -518,9 +519,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -534,9 +535,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -550,9 +551,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -566,9 +567,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -582,9 +583,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -598,9 +599,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ "x64" ], @@ -614,9 +615,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], @@ -630,9 +631,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ "x64" ], @@ -646,9 +647,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ "arm64" ], @@ -662,9 +663,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ "ia32" ], @@ -678,9 +679,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -2133,9 +2134,9 @@ } }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -2145,28 +2146,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/escalade": { @@ -4058,9 +4059,23 @@ } }, "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", + "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -4211,9 +4226,9 @@ } }, "node_modules/rollup": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", - "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.0.tgz", + "integrity": "sha512-nszM8DINnx1vSS+TpbWKMkxem0CDWk3cSit/WWCBVs9/JZ1I/XLwOsiUglYuYReaeWWSsW9kge5zE5NZtf/a4w==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -4593,14 +4608,14 @@ "dev": true }, "node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", + "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -4608,12 +4623,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -4626,6 +4645,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -4751,6 +4773,17 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/vue-plugin-webextension-i18n": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/vue-plugin-webextension-i18n/-/vue-plugin-webextension-i18n-0.1.3.tgz", + "integrity": "sha512-UA2SXA6smbXG/YeOq+lIIbCVt98qpY+KDJQzvLR/H7Zce8La9tPp5LjrEuu6f+pSQzYPbHqrx6HFVYRAamavzQ==", + "engines": { + "node": ">=7.0.0" + }, + "peerDependencies": { + "vue": "*" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", @@ -5130,156 +5163,156 @@ } }, "@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "dev": true, "optional": true }, @@ -6439,33 +6472,33 @@ } }, "esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "escalade": { @@ -7873,9 +7906,9 @@ "dev": true }, "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", + "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -7984,9 +8017,9 @@ } }, "rollup": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", - "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.0.tgz", + "integrity": "sha512-nszM8DINnx1vSS+TpbWKMkxem0CDWk3cSit/WWCBVs9/JZ1I/XLwOsiUglYuYReaeWWSsW9kge5zE5NZtf/a4w==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -8296,15 +8329,15 @@ "dev": true }, "vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", + "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", "dev": true, "requires": { - "esbuild": "^0.17.5", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "postcss": "^8.4.27", + "rollup": "^3.27.1" } }, "vue": { @@ -8393,6 +8426,12 @@ } } }, + "vue-plugin-webextension-i18n": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/vue-plugin-webextension-i18n/-/vue-plugin-webextension-i18n-0.1.3.tgz", + "integrity": "sha512-UA2SXA6smbXG/YeOq+lIIbCVt98qpY+KDJQzvLR/H7Zce8La9tPp5LjrEuu6f+pSQzYPbHqrx6HFVYRAamavzQ==", + "requires": {} + }, "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/src/App.vue b/src/App.vue index c51ab80..b4a7aa3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -117,7 +117,7 @@ export default { @font-face { font-family: "THICCCBOI"; src: local("THICCCBOI"); - src: url('./extension/static/fonts/TTF/THICCCBOI-Regular.ttf') format('truetype'); + src: url('./assets/fonts/TTF/THICCCBOI-Regular.ttf') format('truetype'); font-weight: normal; font-style: normal; } @@ -125,7 +125,7 @@ export default { @font-face { font-family: "THICCCBOI"; src: local("THICCCBOI-ExtraBold"); - src: url('./extension/static/fonts/TTF/THICCCBOI-ExtraBold.ttf') format('truetype'); + src: url('./assets/fonts/TTF/THICCCBOI-ExtraBold.ttf') format('truetype'); font-weight: bold; font-style: normal; } @@ -133,7 +133,7 @@ export default { /* @font-face { font-family: "THICCCBOI"; src: local("THICCCBOI-ExtraBold"); - src: url('./extension/static/fonts/TTF/THICCCBOI-ExtraBold.ttf') format('truetype'); + src: url('./assets/fonts/TTF/THICCCBOI-ExtraBold.ttf') format('truetype'); font-weight: bold; font-style: normal; } */ diff --git a/src/extension/static/fonts/TTF/THICCCBOI-Black.ttf b/src/assets/fonts/TTF/THICCCBOI-Black.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-Black.ttf rename to src/assets/fonts/TTF/THICCCBOI-Black.ttf diff --git a/src/extension/static/fonts/TTF/THICCCBOI-Bold.ttf b/src/assets/fonts/TTF/THICCCBOI-Bold.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-Bold.ttf rename to src/assets/fonts/TTF/THICCCBOI-Bold.ttf diff --git a/src/extension/static/fonts/TTF/THICCCBOI-ExtraBold.ttf b/src/assets/fonts/TTF/THICCCBOI-ExtraBold.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-ExtraBold.ttf rename to src/assets/fonts/TTF/THICCCBOI-ExtraBold.ttf diff --git a/src/extension/static/fonts/TTF/THICCCBOI-Light.ttf b/src/assets/fonts/TTF/THICCCBOI-Light.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-Light.ttf rename to src/assets/fonts/TTF/THICCCBOI-Light.ttf diff --git a/src/extension/static/fonts/TTF/THICCCBOI-Medium.ttf b/src/assets/fonts/TTF/THICCCBOI-Medium.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-Medium.ttf rename to src/assets/fonts/TTF/THICCCBOI-Medium.ttf diff --git a/src/extension/static/fonts/TTF/THICCCBOI-Regular.ttf b/src/assets/fonts/TTF/THICCCBOI-Regular.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-Regular.ttf rename to src/assets/fonts/TTF/THICCCBOI-Regular.ttf diff --git a/src/extension/static/fonts/TTF/THICCCBOI-SemiBold.ttf b/src/assets/fonts/TTF/THICCCBOI-SemiBold.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-SemiBold.ttf rename to src/assets/fonts/TTF/THICCCBOI-SemiBold.ttf diff --git a/src/extension/static/fonts/TTF/THICCCBOI-ThicccAF.ttf b/src/assets/fonts/TTF/THICCCBOI-ThicccAF.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-ThicccAF.ttf rename to src/assets/fonts/TTF/THICCCBOI-ThicccAF.ttf diff --git a/src/extension/static/fonts/TTF/THICCCBOI-Thin.ttf b/src/assets/fonts/TTF/THICCCBOI-Thin.ttf similarity index 100% rename from src/extension/static/fonts/TTF/THICCCBOI-Thin.ttf rename to src/assets/fonts/TTF/THICCCBOI-Thin.ttf diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-Black.woff2 b/src/assets/fonts/Webfont/THICCCBOI-Black.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-Black.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-Black.woff2 diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-Bold.woff2 b/src/assets/fonts/Webfont/THICCCBOI-Bold.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-Bold.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-Bold.woff2 diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-ExtraBold.woff2 b/src/assets/fonts/Webfont/THICCCBOI-ExtraBold.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-ExtraBold.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-ExtraBold.woff2 diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-Light.woff2 b/src/assets/fonts/Webfont/THICCCBOI-Light.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-Light.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-Light.woff2 diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-Medium.woff2 b/src/assets/fonts/Webfont/THICCCBOI-Medium.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-Medium.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-Medium.woff2 diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-Regular.woff2 b/src/assets/fonts/Webfont/THICCCBOI-Regular.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-Regular.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-Regular.woff2 diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-SemiBold.woff2 b/src/assets/fonts/Webfont/THICCCBOI-SemiBold.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-SemiBold.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-SemiBold.woff2 diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-ThicccAF.woff2 b/src/assets/fonts/Webfont/THICCCBOI-ThicccAF.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-ThicccAF.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-ThicccAF.woff2 diff --git a/src/extension/static/fonts/Webfont/THICCCBOI-Thin.woff2 b/src/assets/fonts/Webfont/THICCCBOI-Thin.woff2 similarity index 100% rename from src/extension/static/fonts/Webfont/THICCCBOI-Thin.woff2 rename to src/assets/fonts/Webfont/THICCCBOI-Thin.woff2 diff --git a/src/extension/favicon.ico b/src/assets/images/favicon.ico similarity index 100% rename from src/extension/favicon.ico rename to src/assets/images/favicon.ico diff --git a/src/extension/assets/icons/favicon.ico b/src/extension/assets/icons/favicon.ico new file mode 100644 index 0000000..0da3e7f Binary files /dev/null and b/src/extension/assets/icons/favicon.ico differ diff --git a/src/extension/icon128.png b/src/extension/assets/icons/icon128.png similarity index 100% rename from src/extension/icon128.png rename to src/extension/assets/icons/icon128.png diff --git a/src/extension/icon48.png b/src/extension/assets/icons/icon48.png similarity index 100% rename from src/extension/icon48.png rename to src/extension/assets/icons/icon48.png diff --git a/src/extension/assets/images/grid_background.png b/src/extension/assets/images/grid_background.png new file mode 100644 index 0000000..0de48c5 Binary files /dev/null and b/src/extension/assets/images/grid_background.png differ diff --git a/src/extension/threatslayer_logo.png b/src/extension/assets/images/threatslayer_logo.png similarity index 100% rename from src/extension/threatslayer_logo.png rename to src/extension/assets/images/threatslayer_logo.png diff --git a/src/extension/banner.css b/src/extension/assets/style/banner.css similarity index 100% rename from src/extension/banner.css rename to src/extension/assets/style/banner.css diff --git a/src/extension/background.js b/src/extension/background.js deleted file mode 100644 index 40413b9..0000000 --- a/src/extension/background.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * This is the main background script for ThreatSlayer. - */ -const baseAPIUrl = 'http://159.89.252.13'; -const betaBaseAPIUrl = 'https://beta.octahedron.interlock.network'; -const surveyUrl = 'https://docs.google.com/forms/d/e/1FAIpQLSeo1gW6Sg_ITlAXxbTXliQdab2qt1cLBzu45mXpz-XJ8O1KPg/viewform'; -const releaseNotes = 'https://github.com/interlock-network/threatslayer/blob/master/docs/release_notes.md'; -const defaultApiKey = 'threatslayer-api-key'; -const defaultConfig = { - method: 'POST', - headers: { 'Content-Type': 'application/json' } -}; - -/** - * This listener is responsible for handling messages from content - * scripts. It is invoked by script.js using - * `chrome.runtime.sendMessage`. - */ -chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { - let selectedBaseAPIUrl = baseAPIUrl; - const url = request.url; - - if (request.contentScriptQuery === 'queryURL') { - chrome.storage.local.get('totalURLsVisited').then((result) => { - let totalURLsVisited = result.totalURLsVisited || 0; - totalURLsVisited++; - - chrome.storage.local - .set({ totalURLsVisited }) - .then(() => { console.log(`Total URLs set to: ${totalURLsVisited}`); }); - }); - - chrome.storage.sync.get('betaAISelected', async function (data) { - if (data.betaAISelected && data.betaAISelected === true) { - console.log('Querying beta AI Threat Detection at', betaBaseAPIUrl); - selectedBaseAPIUrl = betaBaseAPIUrl; - } - - chrome.storage.local.get('apiKey').then((result) => { - const key = result.apiKey || defaultApiKey; - - fetch(`${selectedBaseAPIUrl}/malicious_p`, { - ...defaultConfig, - body: JSON.stringify({ key, url }) - }) - .then((response) => response.json()) - .then((response) => sendResponse(response)) - .catch((error) => { console.log(`Error getting malicious URL: ${error}`) }); - }); - }); - - return true; - } else if (request.action === 'displayWarningBanner') { - chrome.storage.local.get('allowlist').then((result) => { - const allowlist = result.allowlist || []; - - // bail condition - if (allowlist?.includes(url)) { - console.log('URL allowlisted by user:', url); - return; - } - - try { - chrome.storage.local - .get(['totalMaliciousURLsVisited']) - .then((result) => { - let totalMaliciousURLsVisited = result.totalMaliciousURLsVisited || 0; - totalMaliciousURLsVisited++; - - try { - chrome.storage.local - .set({ totalMaliciousURLsVisited }) - .then(() => { - console.log(`Total malicious URLs set to: ${totalMaliciousURLsVisited}`); - }); - } catch (err) { - console.log('Error in setting totalMaliciousURLsVisited:', err); - } - }); - } catch (err) { console.log('Error in getting totalMaliciousURLsVisited:', err); } - - // inject styling - chrome.scripting.insertCSS({ - target: { tabId: sender.tab.id }, - files: ['banner.css'], - }); - // execute script - try { - chrome.scripting - .executeScript({ - target: { tabId: sender.tab.id }, - files: ['banner.js'], - }) - .then((response) => sendResponse(response)); - } catch (err) { console.log('Error in sendingResponse():', err); } - - return true; - }); - } else if (request.action === 'stakeUrl') { - const urlToStake = request.url; - - chrome.storage.local - .set({ urlToStake }) - .then(() => { - console.log(`URL to stake set to: ${urlToStake}`); - chrome.tabs.create({ 'url': chrome.runtime.getURL('index.html'), 'active': true }); - }); - } -}); - -/** - * This listener opens our survey in a new tab when users uninstall - */ -chrome.runtime.setUninstallURL(surveyUrl); - -/** - * This listener opens the release notes in a new tab when users update the extension - */ -chrome.runtime.onInstalled.addListener(function (details) { - if (details.reason == 'update') { - chrome.tabs.create({ url: releaseNotes }); - } -}); - -/** - * This listener opens up our extension page when the user clicks on the pin - */ -chrome.action.onClicked.addListener(() => { - // Send a message to the active tab - chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { - let activeTab = tabs[0]; - - chrome.tabs.sendMessage(activeTab.id, { 'message': 'clicked_browser_action' }); - chrome.tabs.create({ 'url': chrome.runtime.getURL('index.html'), 'active': true }); - }); -}); diff --git a/src/extension/banner.js b/src/extension/banner.js deleted file mode 100644 index 2642398..0000000 --- a/src/extension/banner.js +++ /dev/null @@ -1,176 +0,0 @@ -/** - * This script is injected into website if url is found to be malicious. - */ -(function () { - // create elements - const body = document.body; - const bannerWrapper = document.createElement('div'); - const box = document.createElement('canvas'); - const boxWrapper = document.createElement('div'); - const banner = document.createElement('div'); - const textBox = document.createElement('div'); - const image = document.createElement('img'); - const warningHeadline = document.createElement('h2'); - const bannerTitle = document.createElement('p'); - const bannerText = document.createElement('p'); - const allowButton = document.createElement('button'); - const googleButton = document.createElement('button'); - const stakingHeadline = document.createElement('h2'); - const stakingExplanation = document.createElement('p'); - const stakeButton = document.createElement('button'); - const closeButton = document.createElement('button'); - - // link elements to stylesheet - bannerWrapper.id = 'warningbanner-wrapper'; - box.id = 'box'; - banner.id = 'warningbanner'; - image.id = 'threatslayer_logo'; - warningHeadline.id = 'headline'; - warningHeadline.classList.add('first'); - bannerTitle.classList.add('warningbanner-text'); - bannerTitle.classList.add('first') - bannerText.classList.add('warningbanner-text'); - bannerText.classList.add('first') - textBox.id = 'text-box'; - allowButton.id = 'allow-button'; - allowButton.classList.add('first', 'secondary-button'); - googleButton.id = 'safety-button'; - googleButton.classList.add('first', 'left-button', 'primary-button'); - stakingHeadline.id = 'headline'; - stakingHeadline.classList.add('second'); - stakingExplanation.id = 'staking-explanation'; - stakingExplanation.classList.add('second'); - stakeButton.id = 'stake-button'; - stakeButton.classList.add('second', 'primary-button'); - // stakeButton.style.display = 'none'; - closeButton.id = 'close-button'; - closeButton.classList.add('second', 'secondary-button', 'left-button'); - // closeButton.style.display = 'none'; - - // add background image - backgroundImageURL = chrome.runtime.getURL('grid_background.png'); - banner.style.background = `url(${backgroundImageURL}) repeat`; - - // generate logo URL - imageURL = chrome.runtime.getURL('threatslayer_logo.png'); - image.setAttribute('src', imageURL); - - // "Warning!" / "This website may be malicious." / "Close the tab unless you know this site is safe!" - warningHeadline.appendChild(document.createTextNode(chrome.i18n.getMessage('warning'))); - bannerTitle.appendChild(document.createTextNode(chrome.i18n.getMessage('warning_header'))); - bannerText.appendChild(document.createTextNode(chrome.i18n.getMessage('warning_text'))); - - // "Trust This Site" button - allowButton.appendChild(document.createTextNode(chrome.i18n.getMessage('trust_this_url'))); - googleButton.appendChild(document.createTextNode(chrome.i18n.getMessage('take_to_safety'))); - - // Staking box text and buttons - stakingHeadline.appendChild(document.createTextNode(chrome.i18n.getMessage('staking'))); - stakingExplanation.appendChild(document.createTextNode(chrome.i18n.getMessage('staking_explanation'))); - stakeButton.appendChild(document.createTextNode(chrome.i18n.getMessage('stake_this_url'))); - closeButton.appendChild(document.createTextNode(chrome.i18n.getMessage('close'))); - - // build banner and underlying box - banner.appendChild(image); - banner.append(textBox); - textBox.appendChild(warningHeadline); - textBox.appendChild(bannerTitle); - textBox.appendChild(bannerText); - textBox.appendChild(googleButton); - textBox.appendChild(stakingHeadline); - textBox.appendChild(stakingExplanation); - textBox.appendChild(allowButton); - textBox.appendChild(closeButton); - textBox.appendChild(stakeButton); - - bannerWrapper.appendChild(banner); - boxWrapper.appendChild(box); - - // insert box and banner into page - body.insertBefore(bannerWrapper, body.childNodes[0]); - body.insertBefore(boxWrapper, body.childNodes[0]); - - // on clicking 'Take Me to Safety', go to Google - googleButton.onclick = function () { - window.location.href = 'https://google.com/' - }; - - // on click the close button, remove banner and box - closeButton.onclick = function () { - body.removeChild(bannerWrapper); - body.removeChild(boxWrapper); - } - - // on clicking the stake button, it opens TS+ on the staking page - stakeButton.onclick = function () { - chrome.runtime.sendMessage({ - action: 'stakeUrl', - url: document.URL - }); - - // then remove the warning banner - // TODO move this to a callback? - body.removeChild(bannerWrapper); - body.removeChild(boxWrapper); - } - - // on clicking the allow button, adds URL to local allowlist before sending it to GALACTUS - allowButton.onclick = function () { - // hide initial items on text box - const firstItemsLength = document.getElementsByClassName('first').length; - - for (let i = 0; i < firstItemsLength; i++) { - const firstScreenItem = document.getElementsByClassName('first')[0]; - - firstScreenItem.parentNode.removeChild(firstScreenItem); - } - - // reveal staking items on second screen - const secondItemsLength = document.getElementsByClassName('second').length; - - for (let i = 0; i < secondItemsLength; i++) { - const secondScreenItem = document.getElementsByClassName('second')[0]; - - secondScreenItem.classList.toggle("second"); - } - - chrome.storage.local.get('allowlist').then((result) => { - const allowlist = result.allowlist || []; - const url = document.URL; // this is the current URL to be allowlisted - - // adds URL to local list in Chrome state - if (!allowlist.includes(url)) { - allowlist.push(url); - console.log(`Adding ${url} to allowlist`); - - chrome.storage.local.set({ allowlist }); - } - }); - - // send URL to GALACTUS - chrome.storage.local.get('apiKey').then(async (result) => { - const key = result.apiKey; - const url = document.URL; - const body = { key, url }; - const allowlistUrl = 'http://159.89.252.13/site-unlock' - - try { - const allowlistResult = await fetch(allowlistUrl, { - method: 'POST', - mode: 'cors', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(body) - }); - - console.log('result in allowlist sending', { allowlistResult }.json()); - console.log(`URL ${url} added to allowlist`); - } catch (error) { - console.log('Error sending allowlisted URL:', error); - } - }); - - - }; -})(); diff --git a/src/extension/content/script.js b/src/extension/content/script.js new file mode 100644 index 0000000..3e6b1b4 --- /dev/null +++ b/src/extension/content/script.js @@ -0,0 +1,304 @@ +/** + * This is the main content script used by ThreatSlayer. It is + * executed every time the user visits a page. + */ + +// init +let bannerWrapper, boxWrapper, googleButton, allowButton, stakeButton, closeButton; +const BANNER_CSS = "/assets/style/banner.css"; +const SAFETY_ADDRESS = "https://google.com"; +const SITE_UNLOCK_ENDPOINT = 'http://159.89.252.13/site-unlock/'; + +console.log("INTERLOCK NETWORK: THREATSLAYER IS ACTIVE ON THIS PAGE."); + +/** + * Due to security concerns in content scripts, Chrome requires us to + * execute cross-origin XHR using a service worker. Therefore, we send + * a message to our service worker, which then performs the request, + * and asynchronously provides a response. + * + * (message only returns if url is calssified malicious) + */ +chrome.runtime.sendMessage({message: "scanUrl", url: removeParams(window.location.href)}, async function (response) { + + if (response == "DANGER") { + console.log("THREATSLAYER ALERT: THIS A SUSPICIOUS OR KNOWN MALICIOUS WEBSITE."); + + loadBanner().then(result => { + if (result == "staked") { + chrome.runtime.sendMessage({ + action: 'stakeUrl', + url: document.URL + }); + } + }); + } else { + + console.log("WEBSITE DEEMED SAFE OR UNKNOWN"); + return; + } +}); + +/** + * This injects banner if URL deemed malicious + */ +function loadBanner() { + return new Promise(async (resolve) => { + + loadCSS(); + + // cute as little buttons + googleButton = document.createElement('button'); + googleButton.id = 'safety-button'; + googleButton.classList.add('first', 'left-button', 'primary-button'); + + allowButton = document.createElement('button'); + allowButton.id = 'allow-button'; + allowButton.classList.add('first', 'secondary-button'); + + stakeButton = document.createElement('button'); + stakeButton.id = 'stake-button'; + stakeButton.classList.add('second', 'primary-button'); + // stakeButton.style.display = 'none'; + + closeButton = document.createElement('button'); + closeButton.id = 'close-button'; + closeButton.classList.add('second', 'secondary-button', 'left-button'); + // closeButton.style.display = 'none'; + + // create elements + boxWrapper = document.createElement('div'); + bannerWrapper = document.createElement('div'); + const body = document.body; + const box = document.createElement('canvas'); + const banner = document.createElement('div'); + const textBox = document.createElement('div'); + const image = document.createElement('img'); + const warningHeadline = document.createElement('h2'); + const bannerTitle = document.createElement('p'); + const bannerText = document.createElement('p'); + const stakingHeadline = document.createElement('h2'); + const stakingExplanation = document.createElement('p'); + + // link elements to stylesheet + box.id = 'box'; + boxWrapper.id = 'warningbox-wrapper'; + image.id = 'threatslayer_logo'; + textBox.id = 'text-box'; + warningHeadline.id = 'headline'; + warningHeadline.classList.add('first'); + + banner.id = 'warningbanner'; + bannerWrapper.id = 'warningbanner-wrapper'; + bannerTitle.classList.add('warningbanner-text'); + bannerTitle.classList.add('first') + bannerText.classList.add('warningbanner-text'); + bannerText.classList.add('first') + + stakingHeadline.id = 'headline'; + stakingHeadline.classList.add('second'); + stakingExplanation.id = 'staking-explanation'; + stakingExplanation.classList.add('second'); + + // add background image + backgroundImageURL = chrome.runtime.getURL('/assets/images/grid_background.png'); + banner.style.background = `url(${backgroundImageURL}) repeat`; + + // generate logo URL + imageURL = chrome.runtime.getURL('/assets/images/threatslayer_logo.png'); + image.setAttribute('src', imageURL); + + // "Warning!" / "This website may be malicious." / "Close the tab unless you know this site is safe!" + warningHeadline.appendChild(document.createTextNode(chrome.i18n.getMessage('warning'))); + bannerTitle.appendChild(document.createTextNode(chrome.i18n.getMessage('warning_header'))); + bannerText.appendChild(document.createTextNode(chrome.i18n.getMessage('warning_text'))); + + // "Trust This Site" button + allowButton.appendChild(document.createTextNode(chrome.i18n.getMessage('trust_this_url'))); + googleButton.appendChild(document.createTextNode(chrome.i18n.getMessage('take_to_safety'))); + + // Staking box text and buttons + stakingHeadline.appendChild(document.createTextNode(chrome.i18n.getMessage('staking'))); + stakingExplanation.appendChild(document.createTextNode(chrome.i18n.getMessage('staking_explanation'))); + stakeButton.appendChild(document.createTextNode(chrome.i18n.getMessage('stake_this_url'))); + closeButton.appendChild(document.createTextNode(chrome.i18n.getMessage('close'))); + + // build banner and underlying box + banner.appendChild(image); + banner.append(textBox); + textBox.appendChild(warningHeadline); + textBox.appendChild(bannerTitle); + textBox.appendChild(bannerText); + textBox.appendChild(googleButton); + textBox.appendChild(stakingHeadline); + textBox.appendChild(stakingExplanation); + textBox.appendChild(allowButton); + textBox.appendChild(closeButton); + textBox.appendChild(stakeButton); + + bannerWrapper.appendChild(banner); + boxWrapper.appendChild(box); + + // insert box and banner into page + body.insertBefore(bannerWrapper, body.childNodes[0]); + body.insertBefore(boxWrapper, body.childNodes[0]); + + // Setting up event listeners but delegate logic to the promise-based handlers + googleButton.onclick = async function() { + let result = await handleGoogleButton(); + resolve(result) + }; + allowButton.onclick = async function() { + let result = await handleAllowActions(); + resolve(result); + }; + }); +} + +// this handler processes button event to trust website and present stake and close buttons for final decision +function handleAllowActions() { + return new Promise(async (resolve) => { + + // hide initial items on text box + const firstItemsLength = document.getElementsByClassName('first').length; + + for (let i = 0; i < firstItemsLength; i++) { + const firstScreenItem = document.getElementsByClassName('first')[0]; + + firstScreenItem.parentNode.removeChild(firstScreenItem); + } + + // reveal staking items on second screen + const secondItemsLength = document.getElementsByClassName('second').length; + + for (let i = 0; i < secondItemsLength; i++) { + const secondScreenItem = document.getElementsByClassName('second')[0]; + + secondScreenItem.classList.toggle("second"); + } + + // on clicking the allow button, adds URL to local allowlist before sending it to GALACTUS + // + // send URL to GALACTUS + chrome.storage.local.get('apiKey').then(async (result) => { + const key = result.apiKey; + const url = document.URL; + const body = { key, url }; + const allowlistUrl = SITE_UNLOCK_ENDPOINT; + try { + const allowlistResult = await fetch(allowlistUrl, { + method: 'POST', + mode: 'cors', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(body) + }); + console.log('result in allowlist sending', { allowlistResult }.json()); + console.log(`URL ${url} added to allowlist`); + + } catch (error) { + + console.log('Error sending allowlisted URL:', error); + } + }); + + // update the local allow list + chrome.storage.local.get('allowlist').then((result) => { + + const allowlist = result.allowlist || []; + const url = document.URL; // this is the current URL to be allowlisted + + // adds URL to local list in Chrome state + if (!allowlist.includes(url)) { + allowlist.push(url); + console.log(`Adding ${url} to allowlist`); + + chrome.storage.local.set({ allowlist }); + } + + // now wait for choice to stake or close + handleAllowButton().then((result) => { + + resolve(result) + }); + }); + }); +} + + +// wait for close or stake button events +function handleAllowButton() { + return new Promise((resolve) => { + + // on clicking the stake button, it opens TS+ on the staking page + stakeButton.onclick = function () { + + closeBanner() + resolve("staked"); + } + + // on click the close button, remove banner and box + closeButton.onclick = function () { + + closeBanner(); + resolve("closed"); + } + }); +} + +// run away to the safe space of papa google +function handleGoogleButton() { + return new Promise((resolve) => { + + window.location.href = SAFETY_ADDRESS; + resolve("navigated-to-safety"); + }); +} + +/** + * This function injects banner styling if malicious_p returns 'true' + */ +async function loadCSS() { + let head = document.getElementsByTagName('head')[0]; + let link = document.createElement('link'); + link.id = "malicious_p_banner"; + link.rel = 'stylesheet'; + link.type = 'text/css'; + link.media = 'all'; + link.href = chrome.runtime.getURL(BANNER_CSS) + head.appendChild(link); +} + +/** + * This function closes the warning banner and removes styling + **/ +function closeBanner() { + const head = document.head; + const body = document.body; + const style = document.getElementById("malicious_p_banner"); + bannerWrapper = document.getElementById("warningbanner-wrapper"); + boxWrapper = document.getElementById("warningbox-wrapper"); + + if (style) head.removeChild(style); + if (bannerWrapper) body.removeChild(bannerWrapper); + if (boxWrapper) body.removeChild(boxWrapper); +} + +/** + * This helper function removes parameters from URLs sent to pipeline, + * in order to protect sensitive user info. + * From https://stackoverflow.com/questions/12023430/regex-url-path-from-url + * @param {} url - the complete URL string, including protocol and any params + */ +function removeParams(url) { + console.log(url) + const parser = document.createElement('a'); + parser.href = url; + const {hostname, protocol, pathname} = parser; + + const result = `${protocol}//${hostname}${pathname}`; + + return result +} + diff --git a/src/extension/grid_background.png b/src/extension/grid_background.png deleted file mode 100644 index d96065c..0000000 Binary files a/src/extension/grid_background.png and /dev/null differ diff --git a/src/extension/manifest.json b/src/extension/manifest.json index 9a1d3a8..644bd9b 100644 --- a/src/extension/manifest.json +++ b/src/extension/manifest.json @@ -6,46 +6,44 @@ "author": "Interlock", "version": "1.0.0", "icons": { - "128": "icon128.png" + "48": "assets/icons/icon48.png", + "128": "assets/icons/icon128.png" + }, + "action": { + "default_icon": { + "48": "assets/icons/icon48.png", + "128": "assets/icons/icon128.png" + } }, "content_scripts": [ { "js": [ - "script.js" + "content/script.js" ], "matches": [ - "*://*/*" + "" ] } ], "web_accessible_resources": [ { "resources": [ - "grid_background.png", - "hand48.png", - "threatslayer_logo.png", - "static/style.css", - "static/fonts/Webfont/THICCCBOI-Bold.woff2", - "static/fonts/Webfont/THICCCBOI-Regular.woff2", - "static/fonts/TTF/THICCCBOI-Bold.ttf", - "static/fonts/TTF/THICCCBOI-Regular.ttf" + "assets/*" ], "matches": [ - "*://*/*" + "" ] } ], "background": { - "service_worker": "background.js" + "service_worker": "service/worker.js", + "type": "module" }, - "action": {}, "permissions": [ - "scripting", "storage", - "downloads", "tabs" ], "host_permissions": [ "" ] -} \ No newline at end of file +} diff --git a/src/extension/script.js b/src/extension/script.js deleted file mode 100644 index 105a94e..0000000 --- a/src/extension/script.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * This script is the main content script used by ThreatSlayer. It is - * executed every time the user visits a page. - */ - -/** - * This function handles the response from the API. If the response - * indicates that a URL is malicious, the user will be prompted - * in a new window. If the URL is *not* malicious, - * a console message will be logged. If the API is unresponsive, or - * fails to provide a response for some other reason, a console - * message will be logged. - * - * @param {} response - the response from the API, an object with an attribute of `malicious` - */ - -// TODO clean up commented cruft here -// function handleAPIResponse() { -function handleAPIResponse(response) { - let { href } = window.location; - - chrome.runtime.sendMessage({ - action: 'displayWarningBanner', - url: href - }); - - // if (response === null) { - // console.log(`API Unresponsive. Cannot verify safety of URL ${url} .`); - // } else if (response.malicious === false) { - // console.log(`URL ${url} not classified as malicious.`); - // } else if (response.malicious === true) { - // chrome.runtime.sendMessage({ - // action: 'displayWarningBanner', - // url: url - // }); -} - -/** - * This function returns the current URL. - */ -function getFormattedUrl() { - return window.location.href; -} - -/** - * Due to security concerns in content scripts, Chrome requires us to - * execute cross-origin XHR using a service worker. Therefore, we send - * a message to our service worker, which then performs the request, - * and asynchronously provides a response. - */ -chrome.runtime.sendMessage( - { contentScriptQuery: 'queryURL', url: getFormattedUrl() }, - function (response) { - if (response !== undefined && response !== '') { - handleAPIResponse(response); - } else { - handleAPIResponse(null); - } - }); - diff --git a/src/extension/service/worker.js b/src/extension/service/worker.js new file mode 100644 index 0000000..ddd0ae6 --- /dev/null +++ b/src/extension/service/worker.js @@ -0,0 +1,146 @@ +/** + * This is the ThreatSlayer service-worker module. + */ + +/** + * Declare constants. + */ +const DASHBOARD_INDEX = "/index.html" +const SURVEY_URL = "https://docs.google.com/forms/d/e/1FAIpQLSeo1gW6Sg_ITlAXxbTXliQdab2qt1cLBzu45mXpz-XJ8O1KPg/viewform" +const RELEASE_NOTES_URL = "https://github.com/interlock-network/threatslayer/blob/master/docs/release_notes.md" +const API_KEY = "threatslayer-api-key"; +const BASE_API_URL = `https://octahedron.interlock.network`; +const BETA_BASE_API_URL = `https://beta.octahedron.interlock.network`; +const DEFAULT_CONFIG = { + method: "POST", + headers: { "Content-Type": "application/json" }, // no-cors?? + body: JSON.stringify({ key: API_KEY }), +}; + +/** + * This listener handles messages from content scripts. + */ +chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { + + let selectedBaseAPIUrl = BASE_API_URL; + const url = request.url; + + // first update local count of total urls visited by interlocker + if (request.message === 'scanUrl') { + + chrome.storage.local.get('totalURLsVisited').then((result) => { + let totalURLsVisited = result.totalURLsVisited || 0; + totalURLsVisited++; + + chrome.storage.local + .set({ totalURLsVisited }) + .then(() => { console.log(`Total URLs set to: ${totalURLsVisited}`); }); + }); + + // then adjust scan endpoint to reflect beta option predicate + chrome.storage.sync.get('betaAISelected', async function (data) { + if (data.betaAISelected && data.betaAISelected === true) { + console.log('Querying beta AI Threat Detection at', BETA_BASE_API_URL); + selectedBaseAPIUrl = BETA_BASE_API_URL; + } + + // make the post request to octahedron + chrome.storage.local.get('apiKey').then((result) => { + const key = result.apiKey || API_KEY; + + fetch(`${selectedBaseAPIUrl}/malicious_p`, + {...DEFAULT_CONFIG, body: JSON.stringify({ key, url })}) + .then((response) => response.json()) + .then((data) => { + + if (data.malicious == false) { + //if (data.malicious == true) { + console.log(`URL ${url} classified as malicious.`); + chrome.storage.local.get('allowlist').then((result) => { + + const allowlist = result.allowlist || []; + + // bail condition + if (allowlist?.includes(url)) { + console.log('URL allowlisted by user:', url); + return true + } + try { + chrome.storage.local.get(['totalMaliciousURLsVisited']) + .then((result) => { + let totalMaliciousURLsVisited = result.totalMaliciousURLsVisited || 0; + totalMaliciousURLsVisited++; + + try { + chrome.storage.local.set({ totalMaliciousURLsVisited }) + .then(() => { + + console.log(`Total malicious URLs set to: ${totalMaliciousURLsVisited}`); + }); + } catch (err) { + console.log('Error in setting totalMaliciousURLsVisited:', err); + } + }); + } catch (err) { console.log('Error in getting totalMaliciousURLsVisited:', err); } + + sendResponse("DANGER"); + }); + } else if (data.malicious == false) { + console.log(`URL ${url} is not classified as malicious.`); + sendResponse("SAFE"); + } else { + console.log(`API Unresponsive. Cannot verify safety of URL ${url} .`); + } + return true + }) + .catch((error) => { console.log(`Error processing URL: ${error}`) }); + }); + }); + + return true; + + } else if (request.action === 'stakeUrl') { + + const urlToStake = request.url; + + // if interlocker intends to stake on webpage, handle that here + chrome.storage.local.set({ urlToStake }) + .then(() => { + console.log(`URL to stake set to: ${urlToStake}`); + chrome.tabs.create({ 'url': chrome.runtime.getURL(DASHBOARD_INDEX), 'active': true }); + }); + } +}); + +/** + * This listener opens our survey in a new tab when users uninstall + */ +chrome.runtime.setUninstallURL( + + SURVEY_URL +); + +/** + * This listener opens the release notes in a new tab when users update the extension + */ +chrome.runtime.onInstalled.addListener(function (details) { + + if (details.reason == 'update') { + chrome.tabs.create({ url: RELEASE_NOTES_URL }); + } +}); + +/** + * This listener opens up our extension page when the user clicks on the pin + */ +chrome.action.onClicked.addListener(() => { + + // Send a message to the active tab + chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { + let activeTab = tabs[0]; + + chrome.tabs.sendMessage(activeTab.id, { 'message': 'clicked_browser_action' }); + chrome.tabs.create({ 'url': chrome.runtime.getURL('index.html'), 'active': true }); + }); +}); +