From bcfa816d0d40217137f542290e768230e12c30bb Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Sat, 28 Oct 2023 23:24:50 +0900 Subject: [PATCH] (add) aid utility --- assets/js/mi/aid.ts | 43 ++++++++++ assets/js/mi/aidx.ts | 43 ++++++++++ locales/ja-JP.yml | 7 ++ package.json | 3 +- pages/tools/aid-converter.vue | 79 ++++++++++++++++++ pnpm-lock.yaml | 132 ++++++++++++++++++++++++++++++- server/plugins/i18nRedirector.ts | 3 +- 7 files changed, 307 insertions(+), 3 deletions(-) create mode 100644 assets/js/mi/aid.ts create mode 100644 assets/js/mi/aidx.ts create mode 100644 pages/tools/aid-converter.vue diff --git a/assets/js/mi/aid.ts b/assets/js/mi/aid.ts new file mode 100644 index 00000000..9121d297 --- /dev/null +++ b/assets/js/mi/aid.ts @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +// AID +// 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さ2の[ノイズ文字列] + +import * as crypto from 'crypto'; + +export const aidRegExp = /^[0-9a-z]{10}$/; + +const TIME2000 = 946684800000; +let counter: number; + +if (process.client) { + const arr = window.crypto.getRandomValues(new Uint16Array(2)); + counter = parseInt(arr[0].toString()); +} else { + counter = crypto.randomBytes(2).readUInt16LE(0); +} + +function getTime(time: number): string { + time = time - TIME2000; + if (time < 0) time = 0; + + return time.toString(36).padStart(8, '0'); +} + +function getNoise(): string { + return counter.toString(36).padStart(2, '0').slice(-2); +} + +export function genAid(t: number): string { + if (isNaN(t)) throw new Error('Failed to create AID: Invalid Date'); + counter++; + return getTime(t) + getNoise(); +} + +export function parseAid(id: string): { date: Date; } { + const time = parseInt(id.slice(0, 8), 36) + TIME2000; + return { date: new Date(time) }; +} \ No newline at end of file diff --git a/assets/js/mi/aidx.ts b/assets/js/mi/aidx.ts new file mode 100644 index 00000000..f7c36a4f --- /dev/null +++ b/assets/js/mi/aidx.ts @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +// AIDX +// 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さ4の[個体ID] + 長さ4の[カウンタ] +// (c) mei23 +// https://misskey.m544.net/notes/71899acdcc9859ec5708ac24 + +import { customAlphabet } from 'nanoid'; + +export const aidxRegExp = /^[0-9a-z]{16}$/; + +const TIME2000 = 946684800000; +const TIME_LENGTH = 8; +const NODE_LENGTH = 4; +const NOISE_LENGTH = 4; + +const nodeId = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', NODE_LENGTH)(); +let counter = 0; + +function getTime(time: number): string { + time = time - TIME2000; + if (time < 0) time = 0; + + return time.toString(36).padStart(TIME_LENGTH, '0').slice(-TIME_LENGTH); +} + +function getNoise(): string { + return counter.toString(36).padStart(NOISE_LENGTH, '0').slice(-NOISE_LENGTH); +} + +export function genAidx(t: number): string { + if (isNaN(t)) throw new Error('Failed to create AIDX: Invalid Date'); + counter++; + return getTime(t) + nodeId + getNoise(); +} + +export function parseAidx(id: string): { date: Date; } { + const time = parseInt(id.slice(0, TIME_LENGTH), 36) + TIME2000; + return { date: new Date(time) }; +} \ No newline at end of file diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index fe6a291b..92e36a16 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -191,6 +191,13 @@ _mfmPlayground: clearEmojiCacheDescription: "絵文字が表示されないとき" clearEmojiCache: "絵文字のキャッシュを削除" +_aidConverter: + title: "aid/aidxツール" + aidToDate: "aid/aidx→日付時刻" + dateToAid: "日付時刻→aid/aidx" + mode: "作成するid" + date: "日付時刻" + _api: _permissions: title: "権限" diff --git a/package.json b/package.json index 6e797f88..06029155 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ }, "packageManager": "pnpm@8.6.0", "dependencies": { - "js-yaml": "^4.1.0" + "js-yaml": "^4.1.0", + "nanoid": "^5.0.2" } } diff --git a/pages/tools/aid-converter.vue b/pages/tools/aid-converter.vue new file mode 100644 index 00000000..c7740586 --- /dev/null +++ b/pages/tools/aid-converter.vue @@ -0,0 +1,79 @@ + + + + + \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f047713..e00fc280 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ dependencies: js-yaml: specifier: ^4.1.0 version: 4.1.0 + nanoid: + specifier: ^5.0.2 + version: 5.0.2 devDependencies: '@babel/parser': @@ -1166,6 +1169,33 @@ packages: - supports-color dev: true + /@nuxt/kit@3.8.0: + resolution: {integrity: sha512-oIthQxeMIVs4ESVP5FqLYn8tj0S1sLd+eYreh+dNYgnJ2pTi7+THR12ONBNHjk668jqEe7ErUJ8UlGwqBzgezg==} + engines: {node: ^14.18.0 || >=16.10.0} + dependencies: + '@nuxt/schema': 3.8.0 + c12: 1.5.1 + consola: 3.2.3 + defu: 6.1.2 + globby: 13.2.2 + hash-sum: 2.0.0 + ignore: 5.2.4 + jiti: 1.20.0 + knitwork: 1.0.0 + mlly: 1.4.2 + pathe: 1.1.1 + pkg-types: 1.0.3 + scule: 1.0.0 + semver: 7.5.4 + ufo: 1.3.1 + unctx: 2.3.1 + unimport: 3.4.0 + untyped: 1.4.0 + transitivePeerDependencies: + - rollup + - supports-color + dev: true + /@nuxt/schema@3.7.3: resolution: {integrity: sha512-Uqe3Z9RnAROzv5owQo//PztD9d4csKK6ulwQO1hIAinCh34X7z2zrv9lhm14hlRYU1n7ISEi4S7UeHgL/r8d8A==} engines: {node: ^14.18.0 || >=16.10.0} @@ -1185,6 +1215,26 @@ packages: - supports-color dev: true + /@nuxt/schema@3.8.0: + resolution: {integrity: sha512-VEDVeCjdVowhoY5vIBSz94+SSwmM204jN6TNe/ShBJ2d/vZiy9EtLbhOwqaPNFHwnN1fl/XFHThwJiexdB9D1w==} + engines: {node: ^14.18.0 || >=16.10.0} + dependencies: + '@nuxt/ui-templates': 1.3.1 + consola: 3.2.3 + defu: 6.1.2 + hookable: 5.5.3 + pathe: 1.1.1 + pkg-types: 1.0.3 + postcss-import-resolver: 2.0.0 + std-env: 3.4.3 + ufo: 1.3.1 + unimport: 3.4.0 + untyped: 1.4.0 + transitivePeerDependencies: + - rollup + - supports-color + dev: true + /@nuxt/telemetry@2.5.0: resolution: {integrity: sha512-7vZyOHfCAZg1PuCwy3B87MQOezW4pf8BC3gNDL92FW24BuLF0dl/BbFfxPeRxvjivuj5kkNM78x/qzNRCKfZgw==} hasBin: true @@ -1341,7 +1391,7 @@ packages: /@nuxtjs/mdc@0.1.6: resolution: {integrity: sha512-zJuq5KwU3d1Dlh1sudnpVtIFoap09ZrvO9IAM1iP4tipzSRkgHFbCOTMEmK17Rx7KSdmvBbFP+/4MBaJdj1NqQ==} dependencies: - '@nuxt/kit': 3.7.3 + '@nuxt/kit': 3.8.0 '@types/hast': 3.0.1 '@types/mdast': 4.0.0 '@vue/compiler-core': 3.3.4 @@ -2232,6 +2282,15 @@ packages: - supports-color dev: true + /agent-base@7.1.0: + resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -2499,6 +2558,24 @@ packages: - supports-color dev: true + /c12@1.5.1: + resolution: {integrity: sha512-BWZRJgDEveT8uI+cliCwvYSSSSvb4xKoiiu5S0jaDbKBopQLQF7E+bq9xKk1pTcG+mUa3yXuFO7bD9d8Lr9Xxg==} + dependencies: + chokidar: 3.5.3 + defu: 6.1.2 + dotenv: 16.3.1 + giget: 1.1.3 + jiti: 1.20.0 + mlly: 1.4.2 + ohash: 1.1.3 + pathe: 1.1.1 + perfect-debounce: 1.0.0 + pkg-types: 1.0.3 + rc9: 2.1.1 + transitivePeerDependencies: + - supports-color + dev: true + /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -3583,6 +3660,21 @@ packages: - supports-color dev: true + /giget@1.1.3: + resolution: {integrity: sha512-zHuCeqtfgqgDwvXlR84UNgnJDuUHQcNI5OqWqFxxuk2BshuKbYhJWdxBsEo4PvKqoGh23lUAIvBNpChMLv7/9Q==} + hasBin: true + dependencies: + colorette: 2.0.20 + defu: 6.1.2 + https-proxy-agent: 7.0.2 + mri: 1.2.0 + node-fetch-native: 1.4.0 + pathe: 1.1.1 + tar: 6.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /git-config-path@2.0.0: resolution: {integrity: sha512-qc8h1KIQbJpp+241id3GuAtkdyJ+IK+LIVtkiFTRKRrmddDzs3SI9CvP1QYmWBFvm1I/PWRwj//of8bgAc0ltA==} engines: {node: '>=4'} @@ -3879,6 +3971,16 @@ packages: - supports-color dev: true + /https-proxy-agent@7.0.2: + resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /httpxy@0.1.5: resolution: {integrity: sha512-hqLDO+rfststuyEUTWObQK6zHEEmZ/kaIP2/zclGGZn6X8h/ESTWg+WKecQ/e5k4nPswjzZD+q2VqZIbr15CoQ==} dev: true @@ -5153,6 +5255,12 @@ packages: hasBin: true dev: true + /nanoid@5.0.2: + resolution: {integrity: sha512-2ustYUX1R2rL/Br5B/FMhi8d5/QzvkJ912rBYxskcpu0myTHzSZfTr1LAS2Sm7jxRUObRrSBFoyzwAhL49aVSg==} + engines: {node: ^18 || >=20} + hasBin: true + dev: false + /napi-wasm@1.1.0: resolution: {integrity: sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg==} dev: true @@ -6971,6 +7079,10 @@ packages: resolution: {integrity: sha512-bRn3CsoojyNStCZe0BG0Mt4Nr/4KF+rhFlnNXybgqt5pXHNFRlqinSoQaTrGyzE4X8aHplSb+TorH+COin9Yxw==} dev: true + /ufo@1.3.1: + resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==} + dev: true + /ultrahtml@1.5.2: resolution: {integrity: sha512-qh4mBffhlkiXwDAOxvSGxhL0QEQsTbnP9BozOK3OYPEGvPvdWzvAUaXNtUSMdNsKDtuyjEbyVUPFZ52SSLhLqw==} dev: true @@ -7061,6 +7173,24 @@ packages: - rollup dev: true + /unimport@3.4.0: + resolution: {integrity: sha512-M/lfFEgufIT156QAr/jWHLUn55kEmxBBiQsMxvRSIbquwmeJEyQYgshHDEvQDWlSJrVOOTAgnJ3FvlsrpGkanA==} + dependencies: + '@rollup/pluginutils': 5.0.4(rollup@3.29.2) + escape-string-regexp: 5.0.0 + fast-glob: 3.3.1 + local-pkg: 0.4.3 + magic-string: 0.30.3 + mlly: 1.4.2 + pathe: 1.1.1 + pkg-types: 1.0.3 + scule: 1.0.0 + strip-literal: 1.3.0 + unplugin: 1.5.0 + transitivePeerDependencies: + - rollup + dev: true + /unist-builder@4.0.0: resolution: {integrity: sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg==} dependencies: diff --git a/server/plugins/i18nRedirector.ts b/server/plugins/i18nRedirector.ts index 9f383ab4..4957df78 100644 --- a/server/plugins/i18nRedirector.ts +++ b/server/plugins/i18nRedirector.ts @@ -19,10 +19,11 @@ export default defineNitroPlugin((nitroApp) => { remainingList.push(...(v.match(/]+>/gm) ?? [])); remainingList.push(...(v.match(/\n'); + html.head.push('\n'); html.body = ['\n\n']; html.bodyAppend = []; html.bodyPrepend = [];