Merge branch 'develop'
This commit is contained in:
commit
d078f78602
|
@ -8,6 +8,9 @@
|
|||
# Final accessible URL seen by a user.
|
||||
url: https://example.tld/
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# URL SETTINGS AFTER THAT!
|
||||
|
||||
# ┌───────────────────────┐
|
||||
#───┘ Port and TLS settings └───────────────────────────────────
|
||||
|
||||
|
|
24
.eslintrc
24
.eslintrc
|
@ -1,23 +1,23 @@
|
|||
{
|
||||
"parserOptions": {
|
||||
"parser": "typescript-eslint-parser"
|
||||
"parser": "@typescript-eslint/parser"
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:vue/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"vue/require-v-for-key": false,
|
||||
"vue/max-attributes-per-line": false,
|
||||
"vue/html-indent": false,
|
||||
"vue/html-self-closing": false,
|
||||
"vue/no-unused-vars": false,
|
||||
"vue/attributes-order": false,
|
||||
"vue/require-prop-types": false,
|
||||
"vue/require-default-prop": false,
|
||||
"vue/html-closing-bracket-spacing": false,
|
||||
"vue/singleline-html-element-content-newline": false,
|
||||
"vue/no-v-html": false,
|
||||
"vue/require-v-for-key": 0,
|
||||
"vue/max-attributes-per-line": 0,
|
||||
"vue/html-indent": 0,
|
||||
"vue/html-self-closing": 0,
|
||||
"vue/no-unused-vars": 0,
|
||||
"vue/attributes-order": 0,
|
||||
"vue/require-prop-types": 0,
|
||||
"vue/require-default-prop": 0,
|
||||
"vue/html-closing-bracket-spacing": 0,
|
||||
"vue/singleline-html-element-content-newline": 0,
|
||||
"vue/no-v-html": 0,
|
||||
"no-console": 0,
|
||||
"no-unused-vars": 0,
|
||||
"no-empty": 0
|
||||
|
|
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -17,6 +17,29 @@ npm i -g ts-node
|
|||
npm run migrate
|
||||
```
|
||||
|
||||
11.24.0 (2019/07/05)
|
||||
--------------------
|
||||
注意: このアップデート後に、`node built/tools/accept-migration Init 1000000000000`してください。
|
||||
|
||||
### ✨Improvements
|
||||
* WebAuthnサポート
|
||||
* APNGサポート
|
||||
* アバターファイル選択でimage以外は表示しないように
|
||||
* データベース手動バキューム機能
|
||||
* メールサーバー設定が正しいか確認できるように
|
||||
* ピン止めの上限に達したときエラーを表示するように
|
||||
* AP: attributedTo, to, cc が Array や Object のパターンに対応
|
||||
* AP: object type が Audio, Document, Image, Page, Video のパターンに対応
|
||||
* フォロー解除時に確認ダイアログを表示するように
|
||||
* ユーザー入力ダイアログで、入力時にユーザーの存在を確認するように
|
||||
|
||||
### 🐛Fixes
|
||||
* 自分のインスタンスのルートURIへのリンクが無になる問題を修正
|
||||
* リモートファイルの削除が重い問題を修正
|
||||
* 投稿などの連続したスペースがひとつに纏まるのを修正
|
||||
* MFMのパース修正
|
||||
* マイグレーション時にエラーが出る問題を修正
|
||||
|
||||
11.23.1 (2019/06/25)
|
||||
--------------------
|
||||
### 🐛Fixes
|
||||
|
@ -588,10 +611,9 @@ mongodb:
|
|||
3. migration ブランチに切り替え
|
||||
4. `npm i`
|
||||
5. `npm run build`
|
||||
6. `npm run init`
|
||||
7. `npm run migrate`
|
||||
8. master ブランチに戻す
|
||||
9. enjoy
|
||||
6. `npm run migrate`
|
||||
7. master ブランチに戻す
|
||||
8. enjoy
|
||||
|
||||
10.100.0
|
||||
----------
|
||||
|
|
|
@ -219,8 +219,6 @@ const user = await Users.findOne(userId).then(ensure);
|
|||
```
|
||||
|
||||
### Migration作成方法
|
||||
コードの変更をした後、`ormconfig.json`(`npm run ormconfig`で生成)を用意し、
|
||||
|
||||
```
|
||||
npm i -g ts-node
|
||||
ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:12.1-alpine AS base
|
||||
FROM node:12.5-alpine AS base
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
|
|
|
@ -145,7 +145,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||
<table><tr>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13737140/1adf7835017d479280d90fe8d30aade2/1.png?token-time=2145916800&token-hash=0pdle8h5pDZrww0BDOjdz6zO-HudeGTh36a3qi1biVU%3D" alt="Satsuki Yanagi" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1.jpe?token-time=2145916800&token-hash=CPxGQhKIlEaa6WUcgbyHixyKEhakiw9RFdOhsIJBQ_o%3D" alt="takimura" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17195955/be45e5e14c3e48b2bee0456c84e19df4/4.jpe?token-time=2145916800&token-hash=UslrPVM-8TXOe8AapuNiaFYjcIJgPNcU-fKpGbfGJNI%3D" alt="Damillora" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/83884b38afc74d4cbe83c30a13b10edd/1.png?token-time=2145916800&token-hash=R5Tog8RWg0rguRoCIoir3lThokrdPvs8Utfikhc0nhY%3D" alt="Atsuko Tominaga" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/3.png?token-time=2145916800&token-hash=FTm3WVom4dJ9NwWMU4OpCL_8Yc13WiwEbKrDPyTZTPs%3D" alt="natalie" width="100"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1.jpe?token-time=2145916800&token-hash=EWxXhVbZYH7KB4IDT3joc8TbIg8zPO40x1r5IDn3R7c%3D" alt="Hiratake" width="100"></td>
|
||||
|
@ -156,7 +155,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||
</tr><tr>
|
||||
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
|
||||
<td><a href="https://www.patreon.com/takimura">takimura</a></td>
|
||||
<td><a href="https://www.patreon.com/damillora">Damillora</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=16900731">Atsuko Tominaga</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=4389829">natalie</a></td>
|
||||
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
|
||||
|
@ -177,7 +175,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||
</tr></table>
|
||||
|
||||
**Last updated:** Tue, 11 Jun 2019 01:46:06 UTC
|
||||
**Last updated:** Mon, 01 Jul 2019 21:44:06 UTC
|
||||
<!-- PATREON_END -->
|
||||
|
||||
:four_leaf_clover: Copyright
|
||||
|
|
|
@ -260,6 +260,7 @@ common:
|
|||
disable-via-mobile: "Neoznačovat příspěvky jako „z mobilu“"
|
||||
load-raw-images: "Zobrazovat obrázky v původní kvalitě"
|
||||
load-remote-media: "Zobrazovat média ze vzdáleného serveru"
|
||||
sync: "Synchronizace"
|
||||
search: "Hledání"
|
||||
delete: "Odstranit"
|
||||
loading: "Načítám..."
|
||||
|
@ -449,6 +450,7 @@ common/views/components/messaging.vue:
|
|||
you: "Vy"
|
||||
no-history: "Žádná historie"
|
||||
user: "Uživatel"
|
||||
group: "Skupina"
|
||||
common/views/components/messaging-room.vue:
|
||||
new-message: "Máte novou zprávu"
|
||||
common/views/components/messaging-room.form.vue:
|
||||
|
@ -466,6 +468,7 @@ common/views/components/nav.vue:
|
|||
repository: "Úložiště"
|
||||
develop: "Vývojáři"
|
||||
feedback: "Zpětná vazba"
|
||||
tos: "Podmínky užívání"
|
||||
common/views/components/note-menu.vue:
|
||||
mention: "Zmínění"
|
||||
detail: "Více"
|
||||
|
@ -984,6 +987,7 @@ admin/views/instance.vue:
|
|||
smtp-auth: "Provést SMTP autentikaci"
|
||||
smtp-user: "SMTP uživatel"
|
||||
smtp-pass: "SMTP heslo"
|
||||
test-email: "Test"
|
||||
serviceworker-config: "ServiceWorker"
|
||||
enable-serviceworker: "Povolit ServiceWorker"
|
||||
vapid-publickey: "VAPID veřejný klíč"
|
||||
|
|
|
@ -1195,6 +1195,7 @@ admin/views/instance.vue:
|
|||
smtp-auth: "Udfør autentifikation af SMTP"
|
||||
smtp-user: "SMTP bruger"
|
||||
smtp-pass: "SMTP adgangskode"
|
||||
test-email: "Test"
|
||||
serviceworker-config: "ServiceWorker"
|
||||
enable-serviceworker: "Aktiver ServiceWorker"
|
||||
serviceworker-info: "Skal være aktiveret for at give push notifikationer."
|
||||
|
|
|
@ -775,6 +775,7 @@ admin/views/instance.vue:
|
|||
invite: "Einladen"
|
||||
save: "Speichern"
|
||||
saved: "Gespeichert"
|
||||
test-email: "Test"
|
||||
admin/views/charts.vue:
|
||||
drive: "Drive"
|
||||
admin/views/drive.vue:
|
||||
|
|
|
@ -523,6 +523,7 @@ common/views/components/note-menu.vue:
|
|||
delete: "Delete"
|
||||
delete-confirm: "Are you sure you want to delete this post?"
|
||||
remote: "Show original note"
|
||||
pin-limit-exceeded: "You can't pin any more posts."
|
||||
common/views/components/user-menu.vue:
|
||||
mention: "Mention"
|
||||
mute: "Mute"
|
||||
|
@ -601,6 +602,8 @@ common/views/components/signin.vue:
|
|||
signin-with-github: "Sign in with GitHub"
|
||||
signin-with-discord: "Sign in with Discord"
|
||||
login-failed: "Logging in has failed. Make sure you have entered the correct username and password."
|
||||
tap-key: "Click on the Security Key to log in"
|
||||
enter-2fa-code: "Enter your verification code"
|
||||
common/views/components/signup.vue:
|
||||
invitation-code: "Invitation code"
|
||||
invitation-info: "If you do not have an invitation code, please contact an <a href=\"{}\">administrator</a>."
|
||||
|
@ -984,7 +987,7 @@ desktop/views/components/settings.2fa.vue:
|
|||
url: "https://www.google.com/landing/2step/"
|
||||
caution: "If you lose access to your registered device, you won't be able to connect to Misskey anymore!"
|
||||
register: "Register a device"
|
||||
already-registered: "This device is already registered"
|
||||
already-registered: "Your account is currently registered to an authenticator application"
|
||||
unregister: "Unregister"
|
||||
unregistered: "Two-factor authentication has been disabled."
|
||||
enter-password: "Enter the password"
|
||||
|
@ -997,6 +1000,15 @@ desktop/views/components/settings.2fa.vue:
|
|||
success: "Settings saved!"
|
||||
failed: "Failed to setup. Please ensure that the token is correct."
|
||||
info: "From the next time you sign in to Misskey, the token displayed on your device will be necessary too, as well as the password."
|
||||
totp-header: "Authenticator App"
|
||||
security-key-header: "Security Key"
|
||||
security-key: "For additional security, you can log in to your account using a hardware Security Key that supports FIDO2. When you then sign in, you'll need the registered Security Key, or an authenticator app with you."
|
||||
last-used: "Last used:"
|
||||
activate-key: "Click to activate the Security Key"
|
||||
security-key-name: "Name the Key"
|
||||
register-security-key: "Complete Key registration"
|
||||
something-went-wrong: "Wow! There was a problem registering the Key:"
|
||||
key-unregistered: "The Key has been deleted"
|
||||
common/views/components/media-image.vue:
|
||||
sensitive: "NSFW"
|
||||
click-to-show: "Click to show"
|
||||
|
@ -1110,6 +1122,9 @@ admin/views/index.vue:
|
|||
back-to-misskey: "Back to Misskey"
|
||||
admin/views/db.vue:
|
||||
tables: "Tables"
|
||||
vacuum: "Vacuum"
|
||||
vacuum-info: "Tidies up the database. Keeps the data intact and reduces disk usage. This is usually done automatically and periodically."
|
||||
vacuum-exclamation: "Vacuuming can overload the database for a while, and cause users not to be able to participate in interactions."
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "Dashboard"
|
||||
accounts: "Accounts"
|
||||
|
@ -1244,6 +1259,7 @@ admin/views/instance.vue:
|
|||
smtp-auth: "Perform SMTP authentication"
|
||||
smtp-user: "SMTP User"
|
||||
smtp-pass: "SMTP Password"
|
||||
test-email: "Test"
|
||||
serviceworker-config: "ServiceWorker"
|
||||
enable-serviceworker: "Enable ServiceWorker"
|
||||
serviceworker-info: "Must be enabled for push notifications."
|
||||
|
@ -1947,6 +1963,7 @@ pages:
|
|||
_pick:
|
||||
arg1: "Lists"
|
||||
arg2: "Position"
|
||||
listLen: "Get length of list"
|
||||
_listLen:
|
||||
arg1: "Lists"
|
||||
number: "Number"
|
||||
|
|
|
@ -939,6 +939,7 @@ admin/views/instance.vue:
|
|||
smtp-port: "Puerto SMTP"
|
||||
smtp-user: "Usuario SMTP"
|
||||
smtp-pass: "Contraseña SMTP"
|
||||
test-email: "Prueba"
|
||||
admin/views/charts.vue:
|
||||
title: "Gráficos"
|
||||
per-day: "Por día"
|
||||
|
|
|
@ -1217,6 +1217,7 @@ admin/views/instance.vue:
|
|||
smtp-auth: "Effectuer une authentification SMTP"
|
||||
smtp-user: "Utilisateur SMTP"
|
||||
smtp-pass: "Mot de passe SMTP"
|
||||
test-email: "Test"
|
||||
serviceworker-config: "ServiceWorker"
|
||||
enable-serviceworker: "Activer ServiceWorker"
|
||||
serviceworker-info: "Devrait être activé pour les notifications push."
|
||||
|
|
|
@ -36,6 +36,7 @@ common:
|
|||
signout: "ログアウト"
|
||||
reload-to-apply-the-setting: "この設定を反映するにはページをリロードする必要があります。今すぐリロードしますか?"
|
||||
fetching-as-ap-object: "連合に照会中"
|
||||
unfollow-confirm: "{name}さんをフォロー解除しますか?"
|
||||
|
||||
got-it: "わかった"
|
||||
customization-tips:
|
||||
|
@ -561,6 +562,7 @@ common/views/components/note-menu.vue:
|
|||
delete: "削除"
|
||||
delete-confirm: "この投稿を削除しますか?"
|
||||
remote: "投稿元で見る"
|
||||
pin-limit-exceeded: "これ以上ピン留めできません。"
|
||||
|
||||
common/views/components/user-menu.vue:
|
||||
mention: "メンション"
|
||||
|
@ -645,6 +647,8 @@ common/views/components/signin.vue:
|
|||
signin-with-github: "GitHubでログイン"
|
||||
signin-with-discord: "Discordでログイン"
|
||||
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
|
||||
tap-key: "セキュリティキーをクリックしてログイン"
|
||||
enter-2fa-code: "認証コードを入力してください"
|
||||
|
||||
common/views/components/signup.vue:
|
||||
invitation-code: "招待コード"
|
||||
|
@ -1099,6 +1103,15 @@ desktop/views/components/settings.2fa.vue:
|
|||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
totp-header: "認証アプリ"
|
||||
security-key-header: "セキュリティキー"
|
||||
security-key: "セキュリティを強化するために、FIDO2をサポートするハードウェアセキュリティキーを使用してアカウントにログインできます。 サインインの際は、登録されたセキュリティキーまたは認証アプリが必要になります。"
|
||||
last-used: "最後の使用:"
|
||||
activate-key: "クリックしてセキュリティキーをアクティベートしてください"
|
||||
security-key-name: "キー名"
|
||||
register-security-key: "キーの登録を完了"
|
||||
something-went-wrong: "わー! キーを登録する際に問題が発生しました:"
|
||||
key-unregistered: "キーが削除されました"
|
||||
|
||||
common/views/components/media-image.vue:
|
||||
sensitive: "閲覧注意"
|
||||
|
@ -1234,6 +1247,9 @@ admin/views/index.vue:
|
|||
|
||||
admin/views/db.vue:
|
||||
tables: "テーブル"
|
||||
vacuum: "バキューム"
|
||||
vacuum-info: "データベースの掃除を行います。データはそのままで、ディスク使用量を減らします。通常この操作は自動で定期的に行われます。"
|
||||
vacuum-exclamation: "バキュームを行うと、しばらくの間データベースの負荷が高くなり、ユーザーの操作を受け付けなくなる場合があります。"
|
||||
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -1373,6 +1389,7 @@ admin/views/instance.vue:
|
|||
smtp-auth: "SMTP認証を行う"
|
||||
smtp-user: "SMTPユーザー"
|
||||
smtp-pass: "SMTPパスワード"
|
||||
test-email: "テスト"
|
||||
serviceworker-config: "ServiceWorker"
|
||||
enable-serviceworker: "ServiceWorkerを有効にする"
|
||||
serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
|
||||
|
|
|
@ -35,6 +35,7 @@ common:
|
|||
signout: "로그아웃"
|
||||
reload-to-apply-the-setting: "이 설정을 적용하려면 페이지를 새로고침해야 합니다. 바로 새로고침하시겠습니까?"
|
||||
fetching-as-ap-object: "연합에서 조회 중"
|
||||
unfollow-confirm: "{name} 님을 팔로우 해제하시겠습니까?"
|
||||
got-it: "알겠습니다"
|
||||
customization-tips:
|
||||
title: "커스터마이징 도움말"
|
||||
|
@ -523,6 +524,7 @@ common/views/components/note-menu.vue:
|
|||
delete: "삭제"
|
||||
delete-confirm: "이 글을 삭제하시겠습니까?"
|
||||
remote: "글 원본 보기"
|
||||
pin-limit-exceeded: "더 이상 고정할 수 없습니다."
|
||||
common/views/components/user-menu.vue:
|
||||
mention: "멘션"
|
||||
mute: "뮤트"
|
||||
|
@ -601,6 +603,8 @@ common/views/components/signin.vue:
|
|||
signin-with-github: "GitHub으로 로그인"
|
||||
signin-with-discord: "Discord로 로그인"
|
||||
login-failed: "로그인할 수 없습니다. 사용자명과 비밀번호를 확인하여 주십시오."
|
||||
tap-key: "보안 키를 클릭하여 로그인"
|
||||
enter-2fa-code: "인증 코드를 입력하여 주십시오"
|
||||
common/views/components/signup.vue:
|
||||
invitation-code: "초대 코드"
|
||||
invitation-info: "초대 코드가 없으신 분은 <a href=\"{}\">관리자</a>에게 연락하시기 바랍니다."
|
||||
|
@ -997,6 +1001,15 @@ desktop/views/components/settings.2fa.vue:
|
|||
success: "설정이 완료되었습니다!"
|
||||
failed: "설정에 실패했습니다. 토큰이 잘못되었는지 확인해주십시오."
|
||||
info: "다음 로그인부터는 이와 동일하게 비밀번호에 더해 장치에 표시된 토큰을 입력합니다."
|
||||
totp-header: "인증 앱"
|
||||
security-key-header: "보안 키"
|
||||
security-key: "보안을 강화하려면 FIDO2를 지원하는 하드웨어 보안 키를 사용하여 계정에 로그인할 수 있습니다. 로그인 시 등록하였던 보안 키 또는 인증 앱이 필요하게 됩니다."
|
||||
last-used: "마지막 사용:"
|
||||
activate-key: "클릭하여 보안 키를 활성화하여 주십시오"
|
||||
security-key-name: "키 이름"
|
||||
register-security-key: "키 등록 완료"
|
||||
something-went-wrong: "으악! 키를 등록하는 도중 문제가 발생하였습니다:"
|
||||
key-unregistered: "키가 등록되어 있지 않습니다"
|
||||
common/views/components/media-image.vue:
|
||||
sensitive: "열람주의"
|
||||
click-to-show: "클릭하여 보기"
|
||||
|
@ -1110,6 +1123,9 @@ admin/views/index.vue:
|
|||
back-to-misskey: "Misskey로 돌아가기"
|
||||
admin/views/db.vue:
|
||||
tables: "테이블"
|
||||
vacuum: "청소"
|
||||
vacuum-info: "데이터베이스를 청소합니다. 데이터는 그대로인 채로 데이터의 사용량을 줄입니다. 일반적으로 이 작업은 자동으로 정기적으로 수행됩니다."
|
||||
vacuum-exclamation: "청소를 수행하면 한동안 데이터베이스의 부하가 높아져 사용자 조작을 처리하지 못 할 수 있습니다."
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "대시보드"
|
||||
accounts: "계정"
|
||||
|
@ -1244,6 +1260,7 @@ admin/views/instance.vue:
|
|||
smtp-auth: "SMTP 인증 수행"
|
||||
smtp-user: "SMTP 사용자"
|
||||
smtp-pass: "SMTP 비밀번호"
|
||||
test-email: "테스트"
|
||||
serviceworker-config: "ServiceWorker"
|
||||
enable-serviceworker: "ServiceWorker 사용"
|
||||
serviceworker-info: "푸시알림을 수행하려면 사용해야 합니다."
|
||||
|
@ -1947,6 +1964,7 @@ pages:
|
|||
_pick:
|
||||
arg1: "리스트"
|
||||
arg2: "위치"
|
||||
listLen: "리스트의 길이 가져오기"
|
||||
_listLen:
|
||||
arg1: "리스트"
|
||||
number: "수치"
|
||||
|
|
|
@ -65,6 +65,7 @@ common:
|
|||
favorites: "Moje ulubione"
|
||||
permissions:
|
||||
"read:drive": "Wyświetl dysk"
|
||||
"read:messaging": "Zobacz konwersację"
|
||||
"write:votes": "Zagłosuj"
|
||||
empty-timeline-info:
|
||||
explore: "Poznaj"
|
||||
|
@ -72,6 +73,7 @@ common:
|
|||
hide-contents: "Ukryj zawartość"
|
||||
reply-placeholder: "Odpowiedź na ten wpis…"
|
||||
quote-placeholder: "Zacytuj ten wpis…"
|
||||
quote-attached: "Z cytatem"
|
||||
submit: "Wpis"
|
||||
reply: "Odpowiedz"
|
||||
renote: "Udostępnij"
|
||||
|
@ -880,6 +882,7 @@ admin/views/instance.vue:
|
|||
save: "Zapisz"
|
||||
saved: "Zapisano"
|
||||
email: "Adres e-mail"
|
||||
test-email: "Test"
|
||||
admin/views/charts.vue:
|
||||
notes: "Wpisy"
|
||||
users: "Użytkownicy"
|
||||
|
|
|
@ -1244,6 +1244,7 @@ admin/views/instance.vue:
|
|||
smtp-auth: "SMTP身份验证"
|
||||
smtp-user: "SMTP 用户名"
|
||||
smtp-pass: "SMTP 密码"
|
||||
test-email: "测试"
|
||||
serviceworker-config: "ServiceWorker"
|
||||
enable-serviceworker: "启用ServiceWorker"
|
||||
serviceworker-info: "您需要启用推送通知"
|
||||
|
|
485
migration/1000000000000-Init.ts
Normal file
485
migration/1000000000000-Init.ts
Normal file
|
@ -0,0 +1,485 @@
|
|||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class Init1000000000000 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`CREATE TYPE "log_level_enum" AS ENUM('error', 'warning', 'info', 'success', 'debug')`);
|
||||
await queryRunner.query(`CREATE TABLE "log" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "domain" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "level" "log_level_enum" NOT NULL, "worker" character varying(8) NOT NULL, "machine" character varying(128) NOT NULL, "message" character varying(1024) NOT NULL, "data" jsonb NOT NULL DEFAULT '{}', CONSTRAINT "PK_350604cbdf991d5930d9e618fbd" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_8e4eb51a35d81b64dda28eed0a" ON "log" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_8cb40cfc8f3c28261e6f887b03" ON "log" ("domain") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_584b536b49e53ac81beb39a177" ON "log" ("level") `);
|
||||
await queryRunner.query(`CREATE TABLE "drive_folder" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "name" character varying(128) NOT NULL, "userId" character varying(32), "parentId" character varying(32), CONSTRAINT "PK_7a0c089191f5ebdc214e0af808a" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_02878d441ceae15ce060b73daf" ON "drive_folder" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f4fc06e49c0171c85f1c48060d" ON "drive_folder" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_00ceffb0cdc238b3233294f08f" ON "drive_folder" ("parentId") `);
|
||||
await queryRunner.query(`CREATE TABLE "drive_file" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32), "userHost" character varying(128), "md5" character varying(32) NOT NULL, "name" character varying(256) NOT NULL, "type" character varying(128) NOT NULL, "size" integer NOT NULL, "comment" character varying(512), "properties" jsonb NOT NULL DEFAULT '{}', "storedInternal" boolean NOT NULL, "url" character varying(512) NOT NULL, "thumbnailUrl" character varying(512), "webpublicUrl" character varying(512), "accessKey" character varying(256), "thumbnailAccessKey" character varying(256), "webpublicAccessKey" character varying(256), "uri" character varying(512), "src" character varying(512), "folderId" character varying(32), "isSensitive" boolean NOT NULL DEFAULT false, "isLink" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_43ddaaaf18c9e68029b7cbb032e" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_c8dfad3b72196dd1d6b5db168a" ON "drive_file" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_860fa6f6c7df5bb887249fba22" ON "drive_file" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_92779627994ac79277f070c91e" ON "drive_file" ("userHost") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_37bb9a1b4585f8a3beb24c62d6" ON "drive_file" ("md5") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_a40b8df8c989d7db937ea27cf6" ON "drive_file" ("type") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_d85a184c2540d2deba33daf642" ON "drive_file" ("accessKey") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e74022ce9a074b3866f70e0d27" ON "drive_file" ("thumbnailAccessKey") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_c55b2b7c284d9fef98026fc88e" ON "drive_file" ("webpublicAccessKey") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e5848eac4940934e23dbc17581" ON "drive_file" ("uri") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_bb90d1956dafc4068c28aa7560" ON "drive_file" ("folderId") `);
|
||||
await queryRunner.query(`CREATE TABLE "user" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE, "lastFetchedAt" TIMESTAMP WITH TIME ZONE, "username" character varying(128) NOT NULL, "usernameLower" character varying(128) NOT NULL, "name" character varying(128), "followersCount" integer NOT NULL DEFAULT 0, "followingCount" integer NOT NULL DEFAULT 0, "notesCount" integer NOT NULL DEFAULT 0, "avatarId" character varying(32), "bannerId" character varying(32), "tags" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "avatarUrl" character varying(512), "bannerUrl" character varying(512), "avatarColor" character varying(32), "bannerColor" character varying(32), "isSuspended" boolean NOT NULL DEFAULT false, "isSilenced" boolean NOT NULL DEFAULT false, "isLocked" boolean NOT NULL DEFAULT false, "isBot" boolean NOT NULL DEFAULT false, "isCat" boolean NOT NULL DEFAULT false, "isAdmin" boolean NOT NULL DEFAULT false, "isModerator" boolean NOT NULL DEFAULT false, "isVerified" boolean NOT NULL DEFAULT false, "emojis" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "host" character varying(128), "inbox" character varying(512), "sharedInbox" character varying(512), "featured" character varying(512), "uri" character varying(512), "token" character(16), CONSTRAINT "UQ_a854e557b1b14814750c7c7b0c9" UNIQUE ("token"), CONSTRAINT "REL_58f5c71eaab331645112cf8cfa" UNIQUE ("avatarId"), CONSTRAINT "REL_afc64b53f8db3707ceb34eb28e" UNIQUE ("bannerId"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e11e649824a45d8ed01d597fd9" ON "user" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_80ca6e6ef65fb9ef34ea8c90f4" ON "user" ("updatedAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_a27b942a0d6dcff90e3ee9b5e8" ON "user" ("usernameLower") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_fa99d777623947a5b05f394cae" ON "user" ("tags") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_3252a5df8d5bbd16b281f7799e" ON "user" ("host") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_be623adaa4c566baf5d29ce0c8" ON "user" ("uri") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a854e557b1b14814750c7c7b0c" ON "user" ("token") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5deb01ae162d1d70b80d064c27" ON "user" ("usernameLower", "host") `);
|
||||
await queryRunner.query(`CREATE TABLE "app" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32), "secret" character varying(64) NOT NULL, "name" character varying(128) NOT NULL, "description" character varying(512) NOT NULL, "permission" character varying(64) array NOT NULL, "callbackUrl" character varying(512), CONSTRAINT "PK_9478629fc093d229df09e560aea" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_048a757923ed8b157e9895da53" ON "app" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_3f5b0899ef90527a3462d7c2cb" ON "app" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f49922d511d666848f250663c4" ON "app" ("secret") `);
|
||||
await queryRunner.query(`CREATE TABLE "access_token" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "token" character varying(128) NOT NULL, "hash" character varying(128) NOT NULL, "userId" character varying(32) NOT NULL, "appId" character varying(32) NOT NULL, CONSTRAINT "PK_f20f028607b2603deabd8182d12" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_70ba8f6af34bc924fc9e12adb8" ON "access_token" ("token") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_64c327441248bae40f7d92f34f" ON "access_token" ("hash") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_9949557d0e1b2c19e5344c171e" ON "access_token" ("userId") `);
|
||||
await queryRunner.query(`CREATE TYPE "note_visibility_enum" AS ENUM('public', 'home', 'followers', 'specified')`);
|
||||
await queryRunner.query(`CREATE TABLE "note" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "replyId" character varying(32), "renoteId" character varying(32), "text" text, "name" character varying(256), "cw" character varying(512), "appId" character varying(32), "userId" character varying(32) NOT NULL, "viaMobile" boolean NOT NULL DEFAULT false, "localOnly" boolean NOT NULL DEFAULT false, "renoteCount" smallint NOT NULL DEFAULT 0, "repliesCount" smallint NOT NULL DEFAULT 0, "reactions" jsonb NOT NULL DEFAULT '{}', "visibility" "note_visibility_enum" NOT NULL, "uri" character varying(512), "score" integer NOT NULL DEFAULT 0, "fileIds" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], "attachedFileTypes" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "visibleUserIds" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], "mentions" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], "mentionedRemoteUsers" text NOT NULL DEFAULT '[]', "emojis" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "tags" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "hasPoll" boolean NOT NULL DEFAULT false, "geo" jsonb DEFAULT null, "userHost" character varying(128), "replyUserId" character varying(32), "replyUserHost" character varying(128), "renoteUserId" character varying(32), "renoteUserHost" character varying(128), CONSTRAINT "PK_96d0c172a4fba276b1bbed43058" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e7c0567f5261063592f022e9b5" ON "note" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_17cb3553c700a4985dff5a30ff" ON "note" ("replyId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_52ccc804d7c69037d558bac4c9" ON "note" ("renoteId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_5b87d9d19127bd5d92026017a7" ON "note" ("userId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_153536c67d05e9adb24e99fc2b" ON "note" ("uri") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_51c063b6a133a9cb87145450f5" ON "note" ("fileIds") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_25dfc71b0369b003a4cd434d0b" ON "note" ("attachedFileTypes") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_796a8c03959361f97dc2be1d5c" ON "note" ("visibleUserIds") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_54ebcb6d27222913b908d56fd8" ON "note" ("mentions") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_88937d94d7443d9a99a76fa5c0" ON "note" ("tags") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_7125a826ab192eb27e11d358a5" ON "note" ("userHost") `);
|
||||
await queryRunner.query(`CREATE TABLE "poll_vote" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "choice" integer NOT NULL, CONSTRAINT "PK_fd002d371201c472490ba89c6a0" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0fb627e1c2f753262a74f0562d" ON "poll_vote" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_66d2bd2ee31d14bcc23069a89f" ON "poll_vote" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_aecfbd5ef60374918e63ee95fa" ON "poll_vote" ("noteId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_50bd7164c5b78f1f4a42c4d21f" ON "poll_vote" ("userId", "noteId", "choice") `);
|
||||
await queryRunner.query(`CREATE TABLE "note_reaction" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "reaction" character varying(128) NOT NULL, CONSTRAINT "PK_767ec729b108799b587a3fcc9cf" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_01f4581f114e0ebd2bbb876f0b" ON "note_reaction" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_13761f64257f40c5636d0ff95e" ON "note_reaction" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_45145e4953780f3cd5656f0ea6" ON "note_reaction" ("noteId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ad0c221b25672daf2df320a817" ON "note_reaction" ("userId", "noteId") `);
|
||||
await queryRunner.query(`CREATE TABLE "note_watching" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "noteUserId" character varying(32) NOT NULL, CONSTRAINT "PK_49286fdb23725945a74aa27d757" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_318cdf42a9cfc11f479bd802bb" ON "note_watching" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b0134ec406e8d09a540f818288" ON "note_watching" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_03e7028ab8388a3f5e3ce2a861" ON "note_watching" ("noteId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_44499765eec6b5489d72c4253b" ON "note_watching" ("noteUserId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a42c93c69989ce1d09959df4cf" ON "note_watching" ("userId", "noteId") `);
|
||||
await queryRunner.query(`CREATE TABLE "note_unread" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "noteUserId" character varying(32) NOT NULL, "isSpecified" boolean NOT NULL, CONSTRAINT "PK_1904eda61a784f57e6e51fa9c1f" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_56b0166d34ddae49d8ef7610bb" ON "note_unread" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e637cba4dc4410218c4251260e" ON "note_unread" ("noteId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_d908433a4953cc13216cd9c274" ON "note_unread" ("userId", "noteId") `);
|
||||
await queryRunner.query(`CREATE TABLE "notification" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "notifieeId" character varying(32) NOT NULL, "notifierId" character varying(32) NOT NULL, "type" character varying(32) NOT NULL, "isRead" boolean NOT NULL DEFAULT false, "noteId" character varying(32), "reaction" character varying(128), "choice" integer, CONSTRAINT "PK_705b6c7cdf9b2c2ff7ac7872cb7" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b11a5e627c41d4dc3170f1d370" ON "notification" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_3c601b70a1066d2c8b517094cb" ON "notification" ("notifieeId") `);
|
||||
await queryRunner.query(`CREATE TABLE "meta" ("id" character varying(32) NOT NULL, "name" character varying(128), "description" character varying(1024), "maintainerName" character varying(128), "maintainerEmail" character varying(128), "announcements" jsonb NOT NULL DEFAULT '[]', "disableRegistration" boolean NOT NULL DEFAULT false, "disableLocalTimeline" boolean NOT NULL DEFAULT false, "disableGlobalTimeline" boolean NOT NULL DEFAULT false, "enableEmojiReaction" boolean NOT NULL DEFAULT true, "useStarForReactionFallback" boolean NOT NULL DEFAULT false, "langs" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "hiddenTags" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "blockedHosts" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "mascotImageUrl" character varying(512) DEFAULT '/assets/ai.png', "bannerUrl" character varying(512), "errorImageUrl" character varying(512) DEFAULT 'https://xn--931a.moe/aiart/yubitun.png', "iconUrl" character varying(512), "cacheRemoteFiles" boolean NOT NULL DEFAULT true, "proxyAccount" character varying(128), "enableRecaptcha" boolean NOT NULL DEFAULT false, "recaptchaSiteKey" character varying(64), "recaptchaSecretKey" character varying(64), "localDriveCapacityMb" integer NOT NULL DEFAULT 1024, "remoteDriveCapacityMb" integer NOT NULL DEFAULT 32, "maxNoteTextLength" integer NOT NULL DEFAULT 500, "summalyProxy" character varying(128), "enableEmail" boolean NOT NULL DEFAULT false, "email" character varying(128), "smtpSecure" boolean NOT NULL DEFAULT false, "smtpHost" character varying(128), "smtpPort" integer, "smtpUser" character varying(128), "smtpPass" character varying(128), "enableServiceWorker" boolean NOT NULL DEFAULT false, "swPublicKey" character varying(128), "swPrivateKey" character varying(128), "enableTwitterIntegration" boolean NOT NULL DEFAULT false, "twitterConsumerKey" character varying(128), "twitterConsumerSecret" character varying(128), "enableGithubIntegration" boolean NOT NULL DEFAULT false, "githubClientId" character varying(128), "githubClientSecret" character varying(128), "enableDiscordIntegration" boolean NOT NULL DEFAULT false, "discordClientId" character varying(128), "discordClientSecret" character varying(128), CONSTRAINT "PK_c4c17a6c2bd7651338b60fc590b" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TABLE "following" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "followeeId" character varying(32) NOT NULL, "followerId" character varying(32) NOT NULL, "followerHost" character varying(128), "followerInbox" character varying(512), "followerSharedInbox" character varying(512), "followeeHost" character varying(128), "followeeInbox" character varying(512), "followeeSharedInbox" character varying(512), CONSTRAINT "PK_c76c6e044bdf76ecf8bfb82a645" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_582f8fab771a9040a12961f3e7" ON "following" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_24e0042143a18157b234df186c" ON "following" ("followeeId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_6516c5a6f3c015b4eed39978be" ON "following" ("followerId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_307be5f1d1252e0388662acb96" ON "following" ("followerId", "followeeId") `);
|
||||
await queryRunner.query(`CREATE TABLE "instance" ("id" character varying(32) NOT NULL, "caughtAt" TIMESTAMP WITH TIME ZONE NOT NULL, "host" character varying(128) NOT NULL, "system" character varying(64), "usersCount" integer NOT NULL DEFAULT 0, "notesCount" integer NOT NULL DEFAULT 0, "followingCount" integer NOT NULL DEFAULT 0, "followersCount" integer NOT NULL DEFAULT 0, "driveUsage" integer NOT NULL DEFAULT 0, "driveFiles" integer NOT NULL DEFAULT 0, "latestRequestSentAt" TIMESTAMP WITH TIME ZONE, "latestStatus" integer, "latestRequestReceivedAt" TIMESTAMP WITH TIME ZONE, "lastCommunicatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "isNotResponding" boolean NOT NULL DEFAULT false, "isMarkedAsClosed" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_eaf60e4a0c399c9935413e06474" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_2cd3b2a6b4cf0b910b260afe08" ON "instance" ("caughtAt") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_8d5afc98982185799b160e10eb" ON "instance" ("host") `);
|
||||
await queryRunner.query(`CREATE TABLE "muting" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "muteeId" character varying(32) NOT NULL, "muterId" character varying(32) NOT NULL, CONSTRAINT "PK_2e92d06c8b5c602eeb27ca9ba48" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f86d57fbca33c7a4e6897490cc" ON "muting" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_ec96b4fed9dae517e0dbbe0675" ON "muting" ("muteeId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_93060675b4a79a577f31d260c6" ON "muting" ("muterId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_1eb9d9824a630321a29fd3b290" ON "muting" ("muterId", "muteeId") `);
|
||||
await queryRunner.query(`CREATE TABLE "sw_subscription" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "endpoint" character varying(512) NOT NULL, "auth" character varying(256) NOT NULL, "publickey" character varying(128) NOT NULL, CONSTRAINT "PK_e8f763631530051b95eb6279b91" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_97754ca6f2baff9b4abb7f853d" ON "sw_subscription" ("userId") `);
|
||||
await queryRunner.query(`CREATE TABLE "blocking" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "blockeeId" character varying(32) NOT NULL, "blockerId" character varying(32) NOT NULL, CONSTRAINT "PK_e5d9a541cc1965ee7e048ea09dd" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b9a354f7941c1e779f3b33aea6" ON "blocking" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_2cd4a2743a99671308f5417759" ON "blocking" ("blockeeId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0627125f1a8a42c9a1929edb55" ON "blocking" ("blockerId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_98a1bc5cb30dfd159de056549f" ON "blocking" ("blockerId", "blockeeId") `);
|
||||
await queryRunner.query(`CREATE TABLE "user_list" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "name" character varying(128) NOT NULL, CONSTRAINT "PK_87bab75775fd9b1ff822b656402" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b7fcefbdd1c18dce86687531f9" ON "user_list" ("userId") `);
|
||||
await queryRunner.query(`CREATE TABLE "user_list_joining" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "userListId" character varying(32) NOT NULL, CONSTRAINT "PK_11abb3768da1c5f8de101c9df45" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_d844bfc6f3f523a05189076efa" ON "user_list_joining" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_605472305f26818cc93d1baaa7" ON "user_list_joining" ("userListId") `);
|
||||
await queryRunner.query(`CREATE TABLE "hashtag" ("id" character varying(32) NOT NULL, "name" character varying(128) NOT NULL, "mentionedUserIds" character varying(32) array NOT NULL, "mentionedUsersCount" integer NOT NULL DEFAULT 0, "mentionedLocalUserIds" character varying(32) array NOT NULL, "mentionedLocalUsersCount" integer NOT NULL DEFAULT 0, "mentionedRemoteUserIds" character varying(32) array NOT NULL, "mentionedRemoteUsersCount" integer NOT NULL DEFAULT 0, "attachedUserIds" character varying(32) array NOT NULL, "attachedUsersCount" integer NOT NULL DEFAULT 0, "attachedLocalUserIds" character varying(32) array NOT NULL, "attachedLocalUsersCount" integer NOT NULL DEFAULT 0, "attachedRemoteUserIds" character varying(32) array NOT NULL, "attachedRemoteUsersCount" integer NOT NULL DEFAULT 0, CONSTRAINT "PK_cb36eb8af8412bfa978f1165d78" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_347fec870eafea7b26c8a73bac" ON "hashtag" ("name") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_2710a55f826ee236ea1a62698f" ON "hashtag" ("mentionedUsersCount") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0e206cec573f1edff4a3062923" ON "hashtag" ("mentionedLocalUsersCount") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_4c02d38a976c3ae132228c6fce" ON "hashtag" ("mentionedRemoteUsersCount") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_d57f9030cd3af7f63ffb1c267c" ON "hashtag" ("attachedUsersCount") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0c44bf4f680964145f2a68a341" ON "hashtag" ("attachedLocalUsersCount") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0b03cbcd7e6a7ce068efa8ecc2" ON "hashtag" ("attachedRemoteUsersCount") `);
|
||||
await queryRunner.query(`CREATE TABLE "note_favorite" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, CONSTRAINT "PK_af0da35a60b9fa4463a62082b36" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_47f4b1892f5d6ba8efb3057d81" ON "note_favorite" ("userId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0f4fb9ad355f3effff221ef245" ON "note_favorite" ("userId", "noteId") `);
|
||||
await queryRunner.query(`CREATE TABLE "abuse_user_report" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "reporterId" character varying(32) NOT NULL, "comment" character varying(512) NOT NULL, CONSTRAINT "PK_87873f5f5cc5c321a1306b2d18c" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_db2098070b2b5a523c58181f74" ON "abuse_user_report" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_d049123c413e68ca52abe73420" ON "abuse_user_report" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_04cc96756f89d0b7f9473e8cdf" ON "abuse_user_report" ("reporterId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5cd442c3b2e74fdd99dae20243" ON "abuse_user_report" ("userId", "reporterId") `);
|
||||
await queryRunner.query(`CREATE TABLE "registration_ticket" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "code" character varying(64) NOT NULL, CONSTRAINT "PK_f11696b6fafcf3662d4292734f8" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0ff69e8dfa9fe31bb4a4660f59" ON "registration_ticket" ("code") `);
|
||||
await queryRunner.query(`CREATE TABLE "messaging_message" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "recipientId" character varying(32) NOT NULL, "text" character varying(4096), "isRead" boolean NOT NULL DEFAULT false, "fileId" character varying(32), CONSTRAINT "PK_db398fd79dc95d0eb8c30456eaa" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e21cd3646e52ef9c94aaf17c2e" ON "messaging_message" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_5377c307783fce2b6d352e1203" ON "messaging_message" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_cac14a4e3944454a5ce7daa514" ON "messaging_message" ("recipientId") `);
|
||||
await queryRunner.query(`CREATE TABLE "signin" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "ip" character varying(128) NOT NULL, "headers" jsonb NOT NULL, "success" boolean NOT NULL, CONSTRAINT "PK_9e96ddc025712616fc492b3b588" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_2c308dbdc50d94dc625670055f" ON "signin" ("userId") `);
|
||||
await queryRunner.query(`CREATE TABLE "auth_session" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "token" character varying(128) NOT NULL, "userId" character varying(32), "appId" character varying(32) NOT NULL, CONSTRAINT "PK_19354ed146424a728c1112a8cbf" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_62cb09e1129f6ec024ef66e183" ON "auth_session" ("token") `);
|
||||
await queryRunner.query(`CREATE TABLE "follow_request" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "followeeId" character varying(32) NOT NULL, "followerId" character varying(32) NOT NULL, "requestId" character varying(128), "followerHost" character varying(128), "followerInbox" character varying(512), "followerSharedInbox" character varying(512), "followeeHost" character varying(128), "followeeInbox" character varying(512), "followeeSharedInbox" character varying(512), CONSTRAINT "PK_53a9aa3725f7a3deb150b39dbfc" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_12c01c0d1a79f77d9f6c15fadd" ON "follow_request" ("followeeId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_a7fd92dd6dc519e6fb435dd108" ON "follow_request" ("followerId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_d54a512b822fac7ed52800f6b4" ON "follow_request" ("followerId", "followeeId") `);
|
||||
await queryRunner.query(`CREATE TABLE "emoji" ("id" character varying(32) NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE, "name" character varying(128) NOT NULL, "host" character varying(128), "url" character varying(512) NOT NULL, "uri" character varying(512), "type" character varying(64), "aliases" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], CONSTRAINT "PK_df74ce05e24999ee01ea0bc50a3" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b37dafc86e9af007e3295c2781" ON "emoji" ("name") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_5900e907bb46516ddf2871327c" ON "emoji" ("host") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_4f4d35e1256c84ae3d1f0eab10" ON "emoji" ("name", "host") `);
|
||||
await queryRunner.query(`CREATE TABLE "reversi_game" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "startedAt" TIMESTAMP WITH TIME ZONE, "user1Id" character varying(32) NOT NULL, "user2Id" character varying(32) NOT NULL, "user1Accepted" boolean NOT NULL DEFAULT false, "user2Accepted" boolean NOT NULL DEFAULT false, "black" integer, "isStarted" boolean NOT NULL DEFAULT false, "isEnded" boolean NOT NULL DEFAULT false, "winnerId" character varying(32), "surrendered" character varying(32), "logs" jsonb NOT NULL DEFAULT '[]', "map" character varying(64) array NOT NULL, "bw" character varying(32) NOT NULL, "isLlotheo" boolean NOT NULL DEFAULT false, "canPutEverywhere" boolean NOT NULL DEFAULT false, "loopedBoard" boolean NOT NULL DEFAULT false, "form1" jsonb DEFAULT null, "form2" jsonb DEFAULT null, "crc32" character varying(32), CONSTRAINT "PK_76b30eeba71b1193ad7c5311c3f" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b46ec40746efceac604142be1c" ON "reversi_game" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE TABLE "reversi_matching" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "parentId" character varying(32) NOT NULL, "childId" character varying(32) NOT NULL, CONSTRAINT "PK_880bd0afbab232f21c8b9d146cf" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b604d92d6c7aec38627f6eaf16" ON "reversi_matching" ("createdAt") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_3b25402709dd9882048c2bbade" ON "reversi_matching" ("parentId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e247b23a3c9b45f89ec1299d06" ON "reversi_matching" ("childId") `);
|
||||
await queryRunner.query(`CREATE TABLE "user_note_pining" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, CONSTRAINT "PK_a6a2dad4ae000abce2ea9d9b103" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_bfbc6f79ba4007b4ce5097f08d" ON "user_note_pining" ("userId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_410cd649884b501c02d6e72738" ON "user_note_pining" ("userId", "noteId") `);
|
||||
await queryRunner.query(`CREATE TYPE "poll_notevisibility_enum" AS ENUM('public', 'home', 'followers', 'specified')`);
|
||||
await queryRunner.query(`CREATE TABLE "poll" ("noteId" character varying(32) NOT NULL, "expiresAt" TIMESTAMP WITH TIME ZONE, "multiple" boolean NOT NULL, "choices" character varying(128) array NOT NULL DEFAULT '{}'::varchar[], "votes" integer array NOT NULL, "noteVisibility" "poll_notevisibility_enum" NOT NULL, "userId" character varying(32) NOT NULL, "userHost" character varying(128), CONSTRAINT "REL_da851e06d0dfe2ef397d8b1bf1" UNIQUE ("noteId"), CONSTRAINT "PK_da851e06d0dfe2ef397d8b1bf1b" PRIMARY KEY ("noteId"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0610ebcfcfb4a18441a9bcdab2" ON "poll" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_7fa20a12319c7f6dc3aed98c0a" ON "poll" ("userHost") `);
|
||||
await queryRunner.query(`CREATE TABLE "user_keypair" ("userId" character varying(32) NOT NULL, "publicKey" character varying(4096) NOT NULL, "privateKey" character varying(4096) NOT NULL, CONSTRAINT "REL_f4853eb41ab722fe05f81cedeb" UNIQUE ("userId"), CONSTRAINT "PK_f4853eb41ab722fe05f81cedeb6" PRIMARY KEY ("userId"))`);
|
||||
await queryRunner.query(`CREATE TABLE "user_publickey" ("userId" character varying(32) NOT NULL, "keyId" character varying(256) NOT NULL, "keyPem" character varying(4096) NOT NULL, CONSTRAINT "REL_10c146e4b39b443ede016f6736" UNIQUE ("userId"), CONSTRAINT "PK_10c146e4b39b443ede016f6736d" PRIMARY KEY ("userId"))`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_171e64971c780ebd23fae140bb" ON "user_publickey" ("keyId") `);
|
||||
await queryRunner.query(`CREATE TABLE "user_profile" ("userId" character varying(32) NOT NULL, "location" character varying(128), "birthday" character(10), "description" character varying(1024), "fields" jsonb NOT NULL DEFAULT '[]', "url" character varying(512), "email" character varying(128), "emailVerifyCode" character varying(128), "emailVerified" boolean NOT NULL DEFAULT false, "twoFactorTempSecret" character varying(128), "twoFactorSecret" character varying(128), "twoFactorEnabled" boolean NOT NULL DEFAULT false, "password" character varying(128), "clientData" jsonb NOT NULL DEFAULT '{}', "autoWatch" boolean NOT NULL DEFAULT false, "autoAcceptFollowed" boolean NOT NULL DEFAULT false, "alwaysMarkNsfw" boolean NOT NULL DEFAULT false, "carefulBot" boolean NOT NULL DEFAULT false, "twitter" boolean NOT NULL DEFAULT false, "twitterAccessToken" character varying(64) DEFAULT null, "twitterAccessTokenSecret" character varying(64) DEFAULT null, "twitterUserId" character varying(64) DEFAULT null, "twitterScreenName" character varying(64) DEFAULT null, "github" boolean NOT NULL DEFAULT false, "githubAccessToken" character varying(64) DEFAULT null, "githubId" integer DEFAULT null, "githubLogin" character varying(64) DEFAULT null, "discord" boolean NOT NULL DEFAULT false, "discordAccessToken" character varying(64) DEFAULT null, "discordRefreshToken" character varying(64) DEFAULT null, "discordExpiresDate" integer DEFAULT null, "discordId" character varying(64) DEFAULT null, "discordUsername" character varying(64) DEFAULT null, "discordDiscriminator" character varying(64) DEFAULT null, "userHost" character varying(128), CONSTRAINT "REL_51cb79b5555effaf7d69ba1cff" UNIQUE ("userId"), CONSTRAINT "PK_51cb79b5555effaf7d69ba1cff9" PRIMARY KEY ("userId"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_dce530b98e454793dac5ec2f5a" ON "user_profile" ("userHost") `);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__active_users_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__active_users" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__active_users_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_count" bigint NOT NULL, "___remote_count" bigint NOT NULL, CONSTRAINT "PK_317237a9f733b970604a11e314f" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__drive_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__drive" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__drive_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_totalCount" bigint NOT NULL, "___local_totalSize" bigint NOT NULL, "___local_incCount" bigint NOT NULL, "___local_incSize" bigint NOT NULL, "___local_decCount" bigint NOT NULL, "___local_decSize" bigint NOT NULL, "___remote_totalCount" bigint NOT NULL, "___remote_totalSize" bigint NOT NULL, "___remote_incCount" bigint NOT NULL, "___remote_incSize" bigint NOT NULL, "___remote_decCount" bigint NOT NULL, "___remote_decSize" bigint NOT NULL, CONSTRAINT "PK_f96bc548a765cd4b3b354221ce7" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__federation_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__federation" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__federation_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___instance_total" bigint NOT NULL, "___instance_inc" bigint NOT NULL, "___instance_dec" bigint NOT NULL, CONSTRAINT "PK_b39dcd31a0fe1a7757e348e85fd" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__hashtag_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__hashtag" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__hashtag_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_count" bigint NOT NULL, "___remote_count" bigint NOT NULL, CONSTRAINT "PK_c32f1ea2b44a5d2f7881e37f8f9" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__instance_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__instance" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__instance_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___requests_failed" bigint NOT NULL, "___requests_succeeded" bigint NOT NULL, "___requests_received" bigint NOT NULL, "___notes_total" bigint NOT NULL, "___notes_inc" bigint NOT NULL, "___notes_dec" bigint NOT NULL, "___notes_diffs_normal" bigint NOT NULL, "___notes_diffs_reply" bigint NOT NULL, "___notes_diffs_renote" bigint NOT NULL, "___users_total" bigint NOT NULL, "___users_inc" bigint NOT NULL, "___users_dec" bigint NOT NULL, "___following_total" bigint NOT NULL, "___following_inc" bigint NOT NULL, "___following_dec" bigint NOT NULL, "___followers_total" bigint NOT NULL, "___followers_inc" bigint NOT NULL, "___followers_dec" bigint NOT NULL, "___drive_totalFiles" bigint NOT NULL, "___drive_totalUsage" bigint NOT NULL, "___drive_incFiles" bigint NOT NULL, "___drive_incUsage" bigint NOT NULL, "___drive_decFiles" bigint NOT NULL, "___drive_decUsage" bigint NOT NULL, CONSTRAINT "PK_1267c67c7c2d47b4903975f2c00" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__network_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__network" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__network_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___incomingRequests" bigint NOT NULL, "___outgoingRequests" bigint NOT NULL, "___totalTime" bigint NOT NULL, "___incomingBytes" bigint NOT NULL, "___outgoingBytes" bigint NOT NULL, CONSTRAINT "PK_bc4290c2e27fad14ef0c1ca93f3" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__notes_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__notes" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__notes_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_total" bigint NOT NULL, "___local_inc" bigint NOT NULL, "___local_dec" bigint NOT NULL, "___local_diffs_normal" bigint NOT NULL, "___local_diffs_reply" bigint NOT NULL, "___local_diffs_renote" bigint NOT NULL, "___remote_total" bigint NOT NULL, "___remote_inc" bigint NOT NULL, "___remote_dec" bigint NOT NULL, "___remote_diffs_normal" bigint NOT NULL, "___remote_diffs_reply" bigint NOT NULL, "___remote_diffs_renote" bigint NOT NULL, CONSTRAINT "PK_0aec823fa85c7f901bdb3863b14" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__per_user_drive_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__per_user_drive" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__per_user_drive_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___totalCount" bigint NOT NULL, "___totalSize" bigint NOT NULL, "___incCount" bigint NOT NULL, "___incSize" bigint NOT NULL, "___decCount" bigint NOT NULL, "___decSize" bigint NOT NULL, CONSTRAINT "PK_d0ef23d24d666e1a44a0cd3d208" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__per_user_following_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__per_user_following" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__per_user_following_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_followings_total" bigint NOT NULL, "___local_followings_inc" bigint NOT NULL, "___local_followings_dec" bigint NOT NULL, "___local_followers_total" bigint NOT NULL, "___local_followers_inc" bigint NOT NULL, "___local_followers_dec" bigint NOT NULL, "___remote_followings_total" bigint NOT NULL, "___remote_followings_inc" bigint NOT NULL, "___remote_followings_dec" bigint NOT NULL, "___remote_followers_total" bigint NOT NULL, "___remote_followers_inc" bigint NOT NULL, "___remote_followers_dec" bigint NOT NULL, CONSTRAINT "PK_85bb1b540363a29c2fec83bd907" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__per_user_notes_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__per_user_notes" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__per_user_notes_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___total" bigint NOT NULL, "___inc" bigint NOT NULL, "___dec" bigint NOT NULL, "___diffs_normal" bigint NOT NULL, "___diffs_reply" bigint NOT NULL, "___diffs_renote" bigint NOT NULL, CONSTRAINT "PK_334acf6e915af2f29edc11b8e50" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__per_user_reaction_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__per_user_reaction" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__per_user_reaction_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_count" bigint NOT NULL, "___remote_count" bigint NOT NULL, CONSTRAINT "PK_984f54dae441e65b633e8d27a7f" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__test_grouped_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__test_grouped" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__test_grouped_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___foo_total" bigint NOT NULL, "___foo_inc" bigint NOT NULL, "___foo_dec" bigint NOT NULL, CONSTRAINT "PK_f4a2b175d308695af30d4293272" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__test_unique_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__test_unique" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__test_unique_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___foo" bigint NOT NULL, CONSTRAINT "PK_409bac9c97cc612d8500012319d" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__test_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__test" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__test_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___foo_total" bigint NOT NULL, "___foo_inc" bigint NOT NULL, "___foo_dec" bigint NOT NULL, CONSTRAINT "PK_b4bc31dffbd1b785276a3ecfc1e" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE TYPE "__chart__users_span_enum" AS ENUM('hour', 'day')`);
|
||||
await queryRunner.query(`CREATE TABLE "__chart__users" ("id" SERIAL NOT NULL, "date" integer NOT NULL, "group" character varying(128), "span" "__chart__users_span_enum" NOT NULL, "unique" jsonb NOT NULL DEFAULT '{}', "___local_total" bigint NOT NULL, "___local_inc" bigint NOT NULL, "___local_dec" bigint NOT NULL, "___remote_total" bigint NOT NULL, "___remote_inc" bigint NOT NULL, "___remote_dec" bigint NOT NULL, CONSTRAINT "PK_4dfcf2c78d03524b9eb2c99d328" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_folder" ADD CONSTRAINT "FK_f4fc06e49c0171c85f1c48060d2" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_folder" ADD CONSTRAINT "FK_00ceffb0cdc238b3233294f08f2" FOREIGN KEY ("parentId") REFERENCES "drive_folder"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_file" ADD CONSTRAINT "FK_860fa6f6c7df5bb887249fba22e" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_file" ADD CONSTRAINT "FK_bb90d1956dafc4068c28aa7560a" FOREIGN KEY ("folderId") REFERENCES "drive_folder"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD CONSTRAINT "FK_58f5c71eaab331645112cf8cfa5" FOREIGN KEY ("avatarId") REFERENCES "drive_file"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD CONSTRAINT "FK_afc64b53f8db3707ceb34eb28e2" FOREIGN KEY ("bannerId") REFERENCES "drive_file"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "app" ADD CONSTRAINT "FK_3f5b0899ef90527a3462d7c2cb3" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "access_token" ADD CONSTRAINT "FK_9949557d0e1b2c19e5344c171e9" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "access_token" ADD CONSTRAINT "FK_a3ff16c90cc87a82a0b5959e560" FOREIGN KEY ("appId") REFERENCES "app"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_17cb3553c700a4985dff5a30ff5" FOREIGN KEY ("replyId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_52ccc804d7c69037d558bac4c96" FOREIGN KEY ("renoteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_ec5c201576192ba8904c345c5cc" FOREIGN KEY ("appId") REFERENCES "app"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note" ADD CONSTRAINT "FK_5b87d9d19127bd5d92026017a7b" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "poll_vote" ADD CONSTRAINT "FK_66d2bd2ee31d14bcc23069a89f8" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "poll_vote" ADD CONSTRAINT "FK_aecfbd5ef60374918e63ee95fa7" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note_reaction" ADD CONSTRAINT "FK_13761f64257f40c5636d0ff95ee" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note_reaction" ADD CONSTRAINT "FK_45145e4953780f3cd5656f0ea6a" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note_watching" ADD CONSTRAINT "FK_b0134ec406e8d09a540f8182888" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note_watching" ADD CONSTRAINT "FK_03e7028ab8388a3f5e3ce2a8619" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note_unread" ADD CONSTRAINT "FK_56b0166d34ddae49d8ef7610bb9" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note_unread" ADD CONSTRAINT "FK_e637cba4dc4410218c4251260e4" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_3c601b70a1066d2c8b517094cb9" FOREIGN KEY ("notifieeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_3b4e96eec8d36a8bbb9d02aa710" FOREIGN KEY ("notifierId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_769cb6b73a1efe22ddf733ac453" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "following" ADD CONSTRAINT "FK_24e0042143a18157b234df186c3" FOREIGN KEY ("followeeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "following" ADD CONSTRAINT "FK_6516c5a6f3c015b4eed39978be5" FOREIGN KEY ("followerId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "muting" ADD CONSTRAINT "FK_ec96b4fed9dae517e0dbbe0675c" FOREIGN KEY ("muteeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "muting" ADD CONSTRAINT "FK_93060675b4a79a577f31d260c67" FOREIGN KEY ("muterId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "sw_subscription" ADD CONSTRAINT "FK_97754ca6f2baff9b4abb7f853dd" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "blocking" ADD CONSTRAINT "FK_2cd4a2743a99671308f5417759e" FOREIGN KEY ("blockeeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "blocking" ADD CONSTRAINT "FK_0627125f1a8a42c9a1929edb552" FOREIGN KEY ("blockerId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_list" ADD CONSTRAINT "FK_b7fcefbdd1c18dce86687531f99" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_list_joining" ADD CONSTRAINT "FK_d844bfc6f3f523a05189076efaa" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_list_joining" ADD CONSTRAINT "FK_605472305f26818cc93d1baaa74" FOREIGN KEY ("userListId") REFERENCES "user_list"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note_favorite" ADD CONSTRAINT "FK_47f4b1892f5d6ba8efb3057d81a" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "note_favorite" ADD CONSTRAINT "FK_0e00498f180193423c992bc4370" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_d049123c413e68ca52abe734203" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_04cc96756f89d0b7f9473e8cdf3" FOREIGN KEY ("reporterId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_5377c307783fce2b6d352e1203b" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_cac14a4e3944454a5ce7daa5142" FOREIGN KEY ("recipientId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_535def119223ac05ad3fa9ef64b" FOREIGN KEY ("fileId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "signin" ADD CONSTRAINT "FK_2c308dbdc50d94dc625670055f7" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "auth_session" ADD CONSTRAINT "FK_c072b729d71697f959bde66ade0" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "auth_session" ADD CONSTRAINT "FK_dbe037d4bddd17b03a1dc778dee" FOREIGN KEY ("appId") REFERENCES "app"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "follow_request" ADD CONSTRAINT "FK_12c01c0d1a79f77d9f6c15fadd2" FOREIGN KEY ("followeeId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "follow_request" ADD CONSTRAINT "FK_a7fd92dd6dc519e6fb435dd108f" FOREIGN KEY ("followerId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "reversi_game" ADD CONSTRAINT "FK_f7467510c60a45ce5aca6292743" FOREIGN KEY ("user1Id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "reversi_game" ADD CONSTRAINT "FK_6649a4e8c5d5cf32fb03b5da9f6" FOREIGN KEY ("user2Id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "reversi_matching" ADD CONSTRAINT "FK_3b25402709dd9882048c2bbade0" FOREIGN KEY ("parentId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "reversi_matching" ADD CONSTRAINT "FK_e247b23a3c9b45f89ec1299d066" FOREIGN KEY ("childId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_note_pining" ADD CONSTRAINT "FK_bfbc6f79ba4007b4ce5097f08d6" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_note_pining" ADD CONSTRAINT "FK_68881008f7c3588ad7ecae471cf" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "poll" ADD CONSTRAINT "FK_da851e06d0dfe2ef397d8b1bf1b" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_keypair" ADD CONSTRAINT "FK_f4853eb41ab722fe05f81cedeb6" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "FK_10c146e4b39b443ede016f6736d" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" ADD CONSTRAINT "FK_51cb79b5555effaf7d69ba1cff9" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" DROP CONSTRAINT "FK_51cb79b5555effaf7d69ba1cff9"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "FK_10c146e4b39b443ede016f6736d"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_keypair" DROP CONSTRAINT "FK_f4853eb41ab722fe05f81cedeb6"`);
|
||||
await queryRunner.query(`ALTER TABLE "poll" DROP CONSTRAINT "FK_da851e06d0dfe2ef397d8b1bf1b"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_note_pining" DROP CONSTRAINT "FK_68881008f7c3588ad7ecae471cf"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_note_pining" DROP CONSTRAINT "FK_bfbc6f79ba4007b4ce5097f08d6"`);
|
||||
await queryRunner.query(`ALTER TABLE "reversi_matching" DROP CONSTRAINT "FK_e247b23a3c9b45f89ec1299d066"`);
|
||||
await queryRunner.query(`ALTER TABLE "reversi_matching" DROP CONSTRAINT "FK_3b25402709dd9882048c2bbade0"`);
|
||||
await queryRunner.query(`ALTER TABLE "reversi_game" DROP CONSTRAINT "FK_6649a4e8c5d5cf32fb03b5da9f6"`);
|
||||
await queryRunner.query(`ALTER TABLE "reversi_game" DROP CONSTRAINT "FK_f7467510c60a45ce5aca6292743"`);
|
||||
await queryRunner.query(`ALTER TABLE "follow_request" DROP CONSTRAINT "FK_a7fd92dd6dc519e6fb435dd108f"`);
|
||||
await queryRunner.query(`ALTER TABLE "follow_request" DROP CONSTRAINT "FK_12c01c0d1a79f77d9f6c15fadd2"`);
|
||||
await queryRunner.query(`ALTER TABLE "auth_session" DROP CONSTRAINT "FK_dbe037d4bddd17b03a1dc778dee"`);
|
||||
await queryRunner.query(`ALTER TABLE "auth_session" DROP CONSTRAINT "FK_c072b729d71697f959bde66ade0"`);
|
||||
await queryRunner.query(`ALTER TABLE "signin" DROP CONSTRAINT "FK_2c308dbdc50d94dc625670055f7"`);
|
||||
await queryRunner.query(`ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_535def119223ac05ad3fa9ef64b"`);
|
||||
await queryRunner.query(`ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_cac14a4e3944454a5ce7daa5142"`);
|
||||
await queryRunner.query(`ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_5377c307783fce2b6d352e1203b"`);
|
||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_04cc96756f89d0b7f9473e8cdf3"`);
|
||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_d049123c413e68ca52abe734203"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_favorite" DROP CONSTRAINT "FK_0e00498f180193423c992bc4370"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_favorite" DROP CONSTRAINT "FK_47f4b1892f5d6ba8efb3057d81a"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_list_joining" DROP CONSTRAINT "FK_605472305f26818cc93d1baaa74"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_list_joining" DROP CONSTRAINT "FK_d844bfc6f3f523a05189076efaa"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_list" DROP CONSTRAINT "FK_b7fcefbdd1c18dce86687531f99"`);
|
||||
await queryRunner.query(`ALTER TABLE "blocking" DROP CONSTRAINT "FK_0627125f1a8a42c9a1929edb552"`);
|
||||
await queryRunner.query(`ALTER TABLE "blocking" DROP CONSTRAINT "FK_2cd4a2743a99671308f5417759e"`);
|
||||
await queryRunner.query(`ALTER TABLE "sw_subscription" DROP CONSTRAINT "FK_97754ca6f2baff9b4abb7f853dd"`);
|
||||
await queryRunner.query(`ALTER TABLE "muting" DROP CONSTRAINT "FK_93060675b4a79a577f31d260c67"`);
|
||||
await queryRunner.query(`ALTER TABLE "muting" DROP CONSTRAINT "FK_ec96b4fed9dae517e0dbbe0675c"`);
|
||||
await queryRunner.query(`ALTER TABLE "following" DROP CONSTRAINT "FK_6516c5a6f3c015b4eed39978be5"`);
|
||||
await queryRunner.query(`ALTER TABLE "following" DROP CONSTRAINT "FK_24e0042143a18157b234df186c3"`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_769cb6b73a1efe22ddf733ac453"`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_3b4e96eec8d36a8bbb9d02aa710"`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_3c601b70a1066d2c8b517094cb9"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_unread" DROP CONSTRAINT "FK_e637cba4dc4410218c4251260e4"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_unread" DROP CONSTRAINT "FK_56b0166d34ddae49d8ef7610bb9"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_watching" DROP CONSTRAINT "FK_03e7028ab8388a3f5e3ce2a8619"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_watching" DROP CONSTRAINT "FK_b0134ec406e8d09a540f8182888"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_reaction" DROP CONSTRAINT "FK_45145e4953780f3cd5656f0ea6a"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_reaction" DROP CONSTRAINT "FK_13761f64257f40c5636d0ff95ee"`);
|
||||
await queryRunner.query(`ALTER TABLE "poll_vote" DROP CONSTRAINT "FK_aecfbd5ef60374918e63ee95fa7"`);
|
||||
await queryRunner.query(`ALTER TABLE "poll_vote" DROP CONSTRAINT "FK_66d2bd2ee31d14bcc23069a89f8"`);
|
||||
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_5b87d9d19127bd5d92026017a7b"`);
|
||||
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_ec5c201576192ba8904c345c5cc"`);
|
||||
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_52ccc804d7c69037d558bac4c96"`);
|
||||
await queryRunner.query(`ALTER TABLE "note" DROP CONSTRAINT "FK_17cb3553c700a4985dff5a30ff5"`);
|
||||
await queryRunner.query(`ALTER TABLE "access_token" DROP CONSTRAINT "FK_a3ff16c90cc87a82a0b5959e560"`);
|
||||
await queryRunner.query(`ALTER TABLE "access_token" DROP CONSTRAINT "FK_9949557d0e1b2c19e5344c171e9"`);
|
||||
await queryRunner.query(`ALTER TABLE "app" DROP CONSTRAINT "FK_3f5b0899ef90527a3462d7c2cb3"`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP CONSTRAINT "FK_afc64b53f8db3707ceb34eb28e2"`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP CONSTRAINT "FK_58f5c71eaab331645112cf8cfa5"`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_file" DROP CONSTRAINT "FK_bb90d1956dafc4068c28aa7560a"`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_file" DROP CONSTRAINT "FK_860fa6f6c7df5bb887249fba22e"`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_folder" DROP CONSTRAINT "FK_00ceffb0cdc238b3233294f08f2"`);
|
||||
await queryRunner.query(`ALTER TABLE "drive_folder" DROP CONSTRAINT "FK_f4fc06e49c0171c85f1c48060d2"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__users"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__users_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__test"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__test_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__test_unique"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__test_unique_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__test_grouped"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__test_grouped_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__per_user_reaction"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__per_user_reaction_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__per_user_notes"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__per_user_notes_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__per_user_following"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__per_user_following_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__per_user_drive"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__per_user_drive_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__notes"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__notes_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__network"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__network_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__instance"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__instance_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__hashtag"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__hashtag_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__federation"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__federation_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__drive"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__drive_span_enum"`);
|
||||
await queryRunner.query(`DROP TABLE "__chart__active_users"`);
|
||||
await queryRunner.query(`DROP TYPE "__chart__active_users_span_enum"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_dce530b98e454793dac5ec2f5a"`);
|
||||
await queryRunner.query(`DROP TABLE "user_profile"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_171e64971c780ebd23fae140bb"`);
|
||||
await queryRunner.query(`DROP TABLE "user_publickey"`);
|
||||
await queryRunner.query(`DROP TABLE "user_keypair"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_7fa20a12319c7f6dc3aed98c0a"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0610ebcfcfb4a18441a9bcdab2"`);
|
||||
await queryRunner.query(`DROP TABLE "poll"`);
|
||||
await queryRunner.query(`DROP TYPE "poll_notevisibility_enum"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_410cd649884b501c02d6e72738"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_bfbc6f79ba4007b4ce5097f08d"`);
|
||||
await queryRunner.query(`DROP TABLE "user_note_pining"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e247b23a3c9b45f89ec1299d06"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_3b25402709dd9882048c2bbade"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b604d92d6c7aec38627f6eaf16"`);
|
||||
await queryRunner.query(`DROP TABLE "reversi_matching"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b46ec40746efceac604142be1c"`);
|
||||
await queryRunner.query(`DROP TABLE "reversi_game"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_4f4d35e1256c84ae3d1f0eab10"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5900e907bb46516ddf2871327c"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b37dafc86e9af007e3295c2781"`);
|
||||
await queryRunner.query(`DROP TABLE "emoji"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d54a512b822fac7ed52800f6b4"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a7fd92dd6dc519e6fb435dd108"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_12c01c0d1a79f77d9f6c15fadd"`);
|
||||
await queryRunner.query(`DROP TABLE "follow_request"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_62cb09e1129f6ec024ef66e183"`);
|
||||
await queryRunner.query(`DROP TABLE "auth_session"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_2c308dbdc50d94dc625670055f"`);
|
||||
await queryRunner.query(`DROP TABLE "signin"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_cac14a4e3944454a5ce7daa514"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5377c307783fce2b6d352e1203"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e21cd3646e52ef9c94aaf17c2e"`);
|
||||
await queryRunner.query(`DROP TABLE "messaging_message"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0ff69e8dfa9fe31bb4a4660f59"`);
|
||||
await queryRunner.query(`DROP TABLE "registration_ticket"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5cd442c3b2e74fdd99dae20243"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_04cc96756f89d0b7f9473e8cdf"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d049123c413e68ca52abe73420"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_db2098070b2b5a523c58181f74"`);
|
||||
await queryRunner.query(`DROP TABLE "abuse_user_report"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0f4fb9ad355f3effff221ef245"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_47f4b1892f5d6ba8efb3057d81"`);
|
||||
await queryRunner.query(`DROP TABLE "note_favorite"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0b03cbcd7e6a7ce068efa8ecc2"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0c44bf4f680964145f2a68a341"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d57f9030cd3af7f63ffb1c267c"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_4c02d38a976c3ae132228c6fce"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0e206cec573f1edff4a3062923"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_2710a55f826ee236ea1a62698f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_347fec870eafea7b26c8a73bac"`);
|
||||
await queryRunner.query(`DROP TABLE "hashtag"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_605472305f26818cc93d1baaa7"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d844bfc6f3f523a05189076efa"`);
|
||||
await queryRunner.query(`DROP TABLE "user_list_joining"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b7fcefbdd1c18dce86687531f9"`);
|
||||
await queryRunner.query(`DROP TABLE "user_list"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_98a1bc5cb30dfd159de056549f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0627125f1a8a42c9a1929edb55"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_2cd4a2743a99671308f5417759"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b9a354f7941c1e779f3b33aea6"`);
|
||||
await queryRunner.query(`DROP TABLE "blocking"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_97754ca6f2baff9b4abb7f853d"`);
|
||||
await queryRunner.query(`DROP TABLE "sw_subscription"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_1eb9d9824a630321a29fd3b290"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_93060675b4a79a577f31d260c6"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_ec96b4fed9dae517e0dbbe0675"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f86d57fbca33c7a4e6897490cc"`);
|
||||
await queryRunner.query(`DROP TABLE "muting"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_8d5afc98982185799b160e10eb"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_2cd3b2a6b4cf0b910b260afe08"`);
|
||||
await queryRunner.query(`DROP TABLE "instance"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_307be5f1d1252e0388662acb96"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_6516c5a6f3c015b4eed39978be"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_24e0042143a18157b234df186c"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_582f8fab771a9040a12961f3e7"`);
|
||||
await queryRunner.query(`DROP TABLE "following"`);
|
||||
await queryRunner.query(`DROP TABLE "meta"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_3c601b70a1066d2c8b517094cb"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b11a5e627c41d4dc3170f1d370"`);
|
||||
await queryRunner.query(`DROP TABLE "notification"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d908433a4953cc13216cd9c274"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e637cba4dc4410218c4251260e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_56b0166d34ddae49d8ef7610bb"`);
|
||||
await queryRunner.query(`DROP TABLE "note_unread"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a42c93c69989ce1d09959df4cf"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_44499765eec6b5489d72c4253b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_03e7028ab8388a3f5e3ce2a861"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b0134ec406e8d09a540f818288"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_318cdf42a9cfc11f479bd802bb"`);
|
||||
await queryRunner.query(`DROP TABLE "note_watching"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_ad0c221b25672daf2df320a817"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_45145e4953780f3cd5656f0ea6"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_13761f64257f40c5636d0ff95e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_01f4581f114e0ebd2bbb876f0b"`);
|
||||
await queryRunner.query(`DROP TABLE "note_reaction"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_50bd7164c5b78f1f4a42c4d21f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_aecfbd5ef60374918e63ee95fa"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_66d2bd2ee31d14bcc23069a89f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0fb627e1c2f753262a74f0562d"`);
|
||||
await queryRunner.query(`DROP TABLE "poll_vote"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_7125a826ab192eb27e11d358a5"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_88937d94d7443d9a99a76fa5c0"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_54ebcb6d27222913b908d56fd8"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_796a8c03959361f97dc2be1d5c"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_25dfc71b0369b003a4cd434d0b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_51c063b6a133a9cb87145450f5"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_153536c67d05e9adb24e99fc2b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5b87d9d19127bd5d92026017a7"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_52ccc804d7c69037d558bac4c9"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_17cb3553c700a4985dff5a30ff"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e7c0567f5261063592f022e9b5"`);
|
||||
await queryRunner.query(`DROP TABLE "note"`);
|
||||
await queryRunner.query(`DROP TYPE "note_visibility_enum"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_9949557d0e1b2c19e5344c171e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_64c327441248bae40f7d92f34f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_70ba8f6af34bc924fc9e12adb8"`);
|
||||
await queryRunner.query(`DROP TABLE "access_token"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f49922d511d666848f250663c4"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_3f5b0899ef90527a3462d7c2cb"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_048a757923ed8b157e9895da53"`);
|
||||
await queryRunner.query(`DROP TABLE "app"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5deb01ae162d1d70b80d064c27"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a854e557b1b14814750c7c7b0c"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_be623adaa4c566baf5d29ce0c8"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_3252a5df8d5bbd16b281f7799e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_fa99d777623947a5b05f394cae"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a27b942a0d6dcff90e3ee9b5e8"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_80ca6e6ef65fb9ef34ea8c90f4"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e11e649824a45d8ed01d597fd9"`);
|
||||
await queryRunner.query(`DROP TABLE "user"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_bb90d1956dafc4068c28aa7560"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e5848eac4940934e23dbc17581"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_c55b2b7c284d9fef98026fc88e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e74022ce9a074b3866f70e0d27"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d85a184c2540d2deba33daf642"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a40b8df8c989d7db937ea27cf6"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_37bb9a1b4585f8a3beb24c62d6"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_92779627994ac79277f070c91e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_860fa6f6c7df5bb887249fba22"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_c8dfad3b72196dd1d6b5db168a"`);
|
||||
await queryRunner.query(`DROP TABLE "drive_file"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_00ceffb0cdc238b3233294f08f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f4fc06e49c0171c85f1c48060d"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_02878d441ceae15ce060b73daf"`);
|
||||
await queryRunner.query(`DROP TABLE "drive_folder"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_584b536b49e53ac81beb39a177"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_8cb40cfc8f3c28261e6f887b03"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_8e4eb51a35d81b64dda28eed0a"`);
|
||||
await queryRunner.query(`DROP TABLE "log"`);
|
||||
await queryRunner.query(`DROP TYPE "log_level_enum"`);
|
||||
}
|
||||
|
||||
}
|
29
migration/1561706992953-webauthn.ts
Normal file
29
migration/1561706992953-webauthn.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class webauthn1561706992953 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`CREATE TABLE "attestation_challenge" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "challenge" character varying(64) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "registrationChallenge" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_d0ba6786e093f1bcb497572a6b5" PRIMARY KEY ("id", "userId"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f1a461a618fa1755692d0e0d59" ON "attestation_challenge" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_47efb914aed1f72dd39a306c7b" ON "attestation_challenge" ("challenge") `);
|
||||
await queryRunner.query(`CREATE TABLE "user_security_key" ("id" character varying NOT NULL, "userId" character varying(32) NOT NULL, "publicKey" character varying NOT NULL, "lastUsed" TIMESTAMP WITH TIME ZONE NOT NULL, "name" character varying(30) NOT NULL, CONSTRAINT "PK_3e508571121ab39c5f85d10c166" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_ff9ca3b5f3ee3d0681367a9b44" ON "user_security_key" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0d7718e562dcedd0aa5cf2c9f7" ON "user_security_key" ("publicKey") `);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" ADD "securityKeysAvailable" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`ALTER TABLE "attestation_challenge" ADD CONSTRAINT "FK_f1a461a618fa1755692d0e0d592" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "user_security_key" ADD CONSTRAINT "FK_ff9ca3b5f3ee3d0681367a9b447" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`ALTER TABLE "user_security_key" DROP CONSTRAINT "FK_ff9ca3b5f3ee3d0681367a9b447"`);
|
||||
await queryRunner.query(`ALTER TABLE "attestation_challenge" DROP CONSTRAINT "FK_f1a461a618fa1755692d0e0d592"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "securityKeysAvailable"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0d7718e562dcedd0aa5cf2c9f7"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_ff9ca3b5f3ee3d0681367a9b44"`);
|
||||
await queryRunner.query(`DROP TABLE "user_security_key"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_47efb914aed1f72dd39a306c7b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f1a461a618fa1755692d0e0d59"`);
|
||||
await queryRunner.query(`DROP TABLE "attestation_challenge"`);
|
||||
}
|
||||
|
||||
}
|
201
migration/1561873850023-ChartIndexes.ts
Normal file
201
migration/1561873850023-ChartIndexes.ts
Normal file
|
@ -0,0 +1,201 @@
|
|||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class ChartIndexes1561873850023 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc" ON "__chart__active_users" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_15e91a03aeeac9dbccdf43fc06" ON "__chart__active_users" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_00ed5f86db1f7efafb1978bf21" ON "__chart__active_users" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_20f57cc8f142c131340ee16742" ON "__chart__active_users" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_9a3ed15a30ab7e3a37702e6e08" ON "__chart__active_users" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_c26e2c1cbb6e911e0554b27416" ON "__chart__active_users" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_13565815f618a1ff53886c5b28" ON "__chart__drive" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_3fa0d0f17ca72e3dc80999a032" ON "__chart__drive" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_7a170f67425e62a8fabb76c872" ON "__chart__drive" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_6e1df243476e20cbf86572ecc0" ON "__chart__drive" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_3313d7288855ec105b5bbf6c21" ON "__chart__drive" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_06690fc959f1c9fdaf21928222" ON "__chart__drive" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_36cb699c49580d4e6c2e6159f9" ON "__chart__federation" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e447064455928cf627590ef527" ON "__chart__federation" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_76e87c7bfc5d925fcbba405d84" ON "__chart__federation" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_2d416e6af791a82e338c79d480" ON "__chart__federation" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_dd907becf76104e4b656659e6b" ON "__chart__federation" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e9cd07672b37d8966cf3709283" ON "__chart__federation" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_07747a1038c05f532a718fe1de" ON "__chart__hashtag" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_fcc181fb8283009c61cc4083ef" ON "__chart__hashtag" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_99a7d2faaef84a6f728d714ad6" ON "__chart__hashtag" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_49975586f50ed7b800fdd88fbd" ON "__chart__hashtag" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_25a97c02003338124b2b75fdbc" ON "__chart__hashtag" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_6d6f156ceefc6bc5f273a0e370" ON "__chart__hashtag" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_6b8f34a1a64b06014b6fb66824" ON "__chart__instance" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_c12f0af4a66cdd30c2287ce8aa" ON "__chart__instance" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_da8a46ba84ca1d8bb5a29bfb63" ON "__chart__instance" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_d0a4f79af5a97b08f37b547197" ON "__chart__instance" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_39ee857ab2f23493037c6b6631" ON "__chart__instance" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f5448d9633cff74208d850aabe" ON "__chart__instance" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_a1efd3e0048a5f2793a47360dc" ON "__chart__network" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f8dd01baeded2ffa833e0a610a" ON "__chart__network" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_7b5da130992ec9df96712d4290" ON "__chart__network" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_08fac0eb3b11f04c200c0b40dd" ON "__chart__network" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0a905b992fecd2b5c3fb98759e" ON "__chart__network" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_9ff6944f01acb756fdc92d7563" ON "__chart__network" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_42eb716a37d381cdf566192b2b" ON "__chart__notes" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e69096589f11e3baa98ddd64d0" ON "__chart__notes" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_7036f2957151588b813185c794" ON "__chart__notes" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0c9a159c5082cbeef3ca6706b5" ON "__chart__notes" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f09d543e3acb16c5976bdb31fa" ON "__chart__notes" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_924fc196c80ca24bae01dd37e4" ON "__chart__notes" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_5f86db6492274e07c1a3cdf286" ON "__chart__per_user_drive" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_328f259961e60c4fa0bfcf55ca" ON "__chart__per_user_drive" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e496ca8096d28f6b9b509264dc" ON "__chart__per_user_drive" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_42ea9381f0fda8dfe0fa1c8b53" ON "__chart__per_user_drive" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_30bf67687f483ace115c5ca642" ON "__chart__per_user_drive" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f2aeafde2ae6fbad38e857631b" ON "__chart__per_user_drive" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_7af07790712aa3438ff6773f3b" ON "__chart__per_user_following" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f92dd6d03f8d994f29987f6214" ON "__chart__per_user_following" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_4b3593098b6edc9c5afe36b18b" ON "__chart__per_user_following" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_57b5458d0d3d6d1e7f13d4e57f" ON "__chart__per_user_following" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b77d4dd9562c3a899d9a286fcd" ON "__chart__per_user_following" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_4db3b84c7be0d3464714f3e0b1" ON "__chart__per_user_following" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_84234bd1abb873f07329681c83" ON "__chart__per_user_notes" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_8d2cbbc8114d90d19b44d626b6" ON "__chart__per_user_notes" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_55bf20f366979f2436de99206b" ON "__chart__per_user_notes" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_046feeb12e9ef5f783f409866a" ON "__chart__per_user_notes" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_5048e9daccbbbc6d567bb142d3" ON "__chart__per_user_notes" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f68a5ab958f9f5fa17a32ac23b" ON "__chart__per_user_notes" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f7bf4c62059764c2c2bb40fdab" ON "__chart__per_user_reaction" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_65633a106bce43fc7c5c30a5c7" ON "__chart__per_user_reaction" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_8cf3156fd7a6b15c43459c6e3b" ON "__chart__per_user_reaction" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_edeb73c09c3143a81bcb34d569" ON "__chart__per_user_reaction" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_229a41ad465f9205f1f5703291" ON "__chart__per_user_reaction" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e316f01a6d24eb31db27f88262" ON "__chart__per_user_reaction" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0c641990ecf47d2545df4edb75" ON "__chart__test_grouped" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_2be7ec6cebddc14dc11e206686" ON "__chart__test_grouped" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_234dff3c0b56a6150b95431ab9" ON "__chart__test_grouped" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_a5133470f4825902e170328ca5" ON "__chart__test_grouped" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b14489029e4b3aaf4bba5fb524" ON "__chart__test_grouped" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_84e661abb7bd1e51b690d4b017" ON "__chart__test_grouped" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_437bab3c6061d90f6bb65fd2cc" ON "__chart__test_unique" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_5c73bf61da4f6e6f15bae88ed1" ON "__chart__test_unique" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_bbfa573a8181018851ed0b6357" ON "__chart__test_unique" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_d70c86baedc68326be11f9c0ce" ON "__chart__test_unique" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_a0cd75442dd10d0643a17c4a49" ON "__chart__test_unique" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_66e1e1ecd2f29e57778af35b59" ON "__chart__test_unique" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b070a906db04b44c67c6c2144d" ON "__chart__test" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_92255988735563f0fe4aba1f05" ON "__chart__test" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_d41cce6aee1a50bfc062038f9b" ON "__chart__test" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_c5870993e25c3d5771f91f5003" ON "__chart__test" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_a319e5dbf47e8a17497623beae" ON "__chart__test" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f170de677ea75ad4533de2723e" ON "__chart__test" ("span", "date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_845254b3eaf708ae8a6cac3026" ON "__chart__users" ("date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_7c184198ecf66a8d3ecb253ab3" ON "__chart__users" ("span") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_ed9b95919c672a13008e9487ee" ON "__chart__users" ("group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_f091abb24193d50c653c6b77fc" ON "__chart__users" ("span", "date") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_337e9599f278bd7537fe30876f" ON "__chart__users" ("date", "group") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_a770a57c70e668cc61590c9161" ON "__chart__users" ("span", "date", "group") `);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.query(`DROP INDEX "IDX_a770a57c70e668cc61590c9161"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_337e9599f278bd7537fe30876f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f091abb24193d50c653c6b77fc"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_ed9b95919c672a13008e9487ee"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_7c184198ecf66a8d3ecb253ab3"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_845254b3eaf708ae8a6cac3026"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f170de677ea75ad4533de2723e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a319e5dbf47e8a17497623beae"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_c5870993e25c3d5771f91f5003"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d41cce6aee1a50bfc062038f9b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_92255988735563f0fe4aba1f05"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b070a906db04b44c67c6c2144d"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_66e1e1ecd2f29e57778af35b59"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a0cd75442dd10d0643a17c4a49"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d70c86baedc68326be11f9c0ce"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_bbfa573a8181018851ed0b6357"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5c73bf61da4f6e6f15bae88ed1"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_437bab3c6061d90f6bb65fd2cc"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_84e661abb7bd1e51b690d4b017"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b14489029e4b3aaf4bba5fb524"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a5133470f4825902e170328ca5"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_234dff3c0b56a6150b95431ab9"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_2be7ec6cebddc14dc11e206686"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0c641990ecf47d2545df4edb75"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e316f01a6d24eb31db27f88262"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_229a41ad465f9205f1f5703291"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_edeb73c09c3143a81bcb34d569"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_8cf3156fd7a6b15c43459c6e3b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_65633a106bce43fc7c5c30a5c7"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f7bf4c62059764c2c2bb40fdab"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f68a5ab958f9f5fa17a32ac23b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5048e9daccbbbc6d567bb142d3"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_046feeb12e9ef5f783f409866a"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_55bf20f366979f2436de99206b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_8d2cbbc8114d90d19b44d626b6"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_84234bd1abb873f07329681c83"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_4db3b84c7be0d3464714f3e0b1"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_b77d4dd9562c3a899d9a286fcd"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_57b5458d0d3d6d1e7f13d4e57f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_4b3593098b6edc9c5afe36b18b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f92dd6d03f8d994f29987f6214"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_7af07790712aa3438ff6773f3b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f2aeafde2ae6fbad38e857631b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_30bf67687f483ace115c5ca642"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_42ea9381f0fda8dfe0fa1c8b53"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e496ca8096d28f6b9b509264dc"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_328f259961e60c4fa0bfcf55ca"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5f86db6492274e07c1a3cdf286"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_924fc196c80ca24bae01dd37e4"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f09d543e3acb16c5976bdb31fa"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0c9a159c5082cbeef3ca6706b5"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_7036f2957151588b813185c794"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e69096589f11e3baa98ddd64d0"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_42eb716a37d381cdf566192b2b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_9ff6944f01acb756fdc92d7563"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0a905b992fecd2b5c3fb98759e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_08fac0eb3b11f04c200c0b40dd"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_7b5da130992ec9df96712d4290"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f8dd01baeded2ffa833e0a610a"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a1efd3e0048a5f2793a47360dc"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f5448d9633cff74208d850aabe"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_39ee857ab2f23493037c6b6631"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_d0a4f79af5a97b08f37b547197"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_da8a46ba84ca1d8bb5a29bfb63"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_c12f0af4a66cdd30c2287ce8aa"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_6b8f34a1a64b06014b6fb66824"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_6d6f156ceefc6bc5f273a0e370"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_25a97c02003338124b2b75fdbc"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_49975586f50ed7b800fdd88fbd"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_99a7d2faaef84a6f728d714ad6"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_fcc181fb8283009c61cc4083ef"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_07747a1038c05f532a718fe1de"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e9cd07672b37d8966cf3709283"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_dd907becf76104e4b656659e6b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_2d416e6af791a82e338c79d480"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_76e87c7bfc5d925fcbba405d84"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e447064455928cf627590ef527"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_36cb699c49580d4e6c2e6159f9"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_06690fc959f1c9fdaf21928222"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_3313d7288855ec105b5bbf6c21"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_6e1df243476e20cbf86572ecc0"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_7a170f67425e62a8fabb76c872"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_3fa0d0f17ca72e3dc80999a032"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_13565815f618a1ff53886c5b28"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_c26e2c1cbb6e911e0554b27416"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_9a3ed15a30ab7e3a37702e6e08"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_20f57cc8f142c131340ee16742"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_00ed5f86db1f7efafb1978bf21"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_15e91a03aeeac9dbccdf43fc06"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_90148bbc2bf0854428786bfc15"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_88937d94d7443d9a99a76fa5c0"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_54ebcb6d27222913b908d56fd8"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_796a8c03959361f97dc2be1d5c"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_25dfc71b0369b003a4cd434d0b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_51c063b6a133a9cb87145450f5"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_fa99d777623947a5b05f394cae"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_315c779174fe8247ab324f036e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_c5d46cbfda48b1c33ed852e21b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_8cb40cfc8f3c28261e6f887b03"`);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import * as fs from 'fs';
|
||||
import config from './config';
|
||||
const config = require('./built/config').default;
|
||||
const entities = require('./built/db/postgre').entities;
|
||||
|
||||
const json = {
|
||||
module.exports = {
|
||||
type: 'postgres',
|
||||
host: config.db.host,
|
||||
port: config.db.port,
|
||||
|
@ -9,11 +9,9 @@ const json = {
|
|||
password: config.db.pass,
|
||||
database: config.db.db,
|
||||
extra: config.db.extra,
|
||||
entities: ['src/models/entities/*.ts'],
|
||||
entities: entities,
|
||||
migrations: ['migration/*.ts'],
|
||||
cli: {
|
||||
migrationsDir: 'migration'
|
||||
}
|
||||
};
|
||||
|
||||
fs.writeFileSync('ormconfig.json', JSON.stringify(json));
|
114
package.json
114
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "11.23.1",
|
||||
"version": "11.24.0",
|
||||
"codename": "daybreak",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -11,9 +11,9 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node ./index.js",
|
||||
"init": "node ./built/init.js",
|
||||
"init": "npm run migrate",
|
||||
"ormconfig": "node ./built/ormconfig.js",
|
||||
"migrate": "npm run ormconfig && ts-node ./node_modules/typeorm/cli.js migration:run",
|
||||
"migrate": "ts-node ./node_modules/typeorm/cli.js migration:run",
|
||||
"migrateandstart": "npm run migrate && npm run start",
|
||||
"build": "webpack && gulp build",
|
||||
"webpack": "webpack",
|
||||
|
@ -30,105 +30,109 @@
|
|||
"video-thumbnail-generator/lodash": "^4.17.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@elastic/elasticsearch": "7.0.0-rc.2",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.15",
|
||||
"@fortawesome/free-brands-svg-icons": "5.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "5.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "5.7.2",
|
||||
"@fortawesome/vue-fontawesome": "0.1.5",
|
||||
"@koa/cors": "2.2.3",
|
||||
"@elastic/elasticsearch": "7.1.0",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.19",
|
||||
"@fortawesome/free-brands-svg-icons": "5.9.0",
|
||||
"@fortawesome/free-regular-svg-icons": "5.9.0",
|
||||
"@fortawesome/free-solid-svg-icons": "5.9.0",
|
||||
"@fortawesome/vue-fontawesome": "0.1.6",
|
||||
"@koa/cors": "3.0.0",
|
||||
"@typescript-eslint/parser": "1.11.0",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/bull": "3.5.11",
|
||||
"@types/bull": "3.5.15",
|
||||
"@types/cbor": "2.0.0",
|
||||
"@types/dateformat": "3.0.0",
|
||||
"@types/deep-equal": "1.0.1",
|
||||
"@types/double-ended-queue": "2.1.0",
|
||||
"@types/double-ended-queue": "2.1.1",
|
||||
"@types/gulp": "4.0.6",
|
||||
"@types/gulp-mocha": "0.0.32",
|
||||
"@types/gulp-rename": "0.0.33",
|
||||
"@types/gulp-replace": "0.0.31",
|
||||
"@types/gulp-uglify": "3.0.6",
|
||||
"@types/gulp-util": "3.0.34",
|
||||
"@types/is-root": "1.0.0",
|
||||
"@types/is-root": "2.1.2",
|
||||
"@types/is-url": "1.2.28",
|
||||
"@types/js-yaml": "3.12.1",
|
||||
"@types/jsdom": "12.2.3",
|
||||
"@types/jsdom": "12.2.4",
|
||||
"@types/katex": "0.10.1",
|
||||
"@types/koa": "2.0.48",
|
||||
"@types/koa": "2.0.49",
|
||||
"@types/koa-bodyparser": "5.0.2",
|
||||
"@types/koa-compress": "2.0.9",
|
||||
"@types/koa-cors": "0.0.0",
|
||||
"@types/koa-favicon": "2.0.19",
|
||||
"@types/koa-logger": "3.1.1",
|
||||
"@types/koa-mount": "3.0.1",
|
||||
"@types/koa-mount": "4.0.0",
|
||||
"@types/koa-multer": "1.0.0",
|
||||
"@types/koa-router": "7.0.40",
|
||||
"@types/koa-router": "7.0.42",
|
||||
"@types/koa-send": "4.1.2",
|
||||
"@types/koa-views": "2.0.3",
|
||||
"@types/koa__cors": "2.2.3",
|
||||
"@types/lolex": "3.1.1",
|
||||
"@types/minio": "7.0.1",
|
||||
"@types/mocha": "5.2.6",
|
||||
"@types/node": "11.13.8",
|
||||
"@types/nodemailer": "4.6.8",
|
||||
"@types/nprogress": "0.0.29",
|
||||
"@types/minio": "7.0.2",
|
||||
"@types/mocha": "5.2.7",
|
||||
"@types/node": "12.0.10",
|
||||
"@types/nodemailer": "6.2.0",
|
||||
"@types/nprogress": "0.2.0",
|
||||
"@types/oauth": "0.9.1",
|
||||
"@types/parse5": "5.0.0",
|
||||
"@types/parsimmon": "1.10.0",
|
||||
"@types/portscanner": "2.1.0",
|
||||
"@types/pug": "2.0.4",
|
||||
"@types/qrcode": "1.3.2",
|
||||
"@types/qrcode": "1.3.3",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/ratelimiter": "2.1.28",
|
||||
"@types/redis": "2.8.12",
|
||||
"@types/redis": "2.8.13",
|
||||
"@types/rename": "1.0.1",
|
||||
"@types/request": "2.48.1",
|
||||
"@types/request-promise-native": "1.0.16",
|
||||
"@types/request-stats": "3.0.0",
|
||||
"@types/rimraf": "2.0.2",
|
||||
"@types/seedrandom": "2.4.28",
|
||||
"@types/sharp": "0.22.1",
|
||||
"@types/showdown": "1.9.2",
|
||||
"@types/sharp": "0.22.2",
|
||||
"@types/showdown": "1.9.3",
|
||||
"@types/speakeasy": "2.0.4",
|
||||
"@types/systeminformation": "3.23.1",
|
||||
"@types/tinycolor2": "1.4.1",
|
||||
"@types/tinycolor2": "1.4.2",
|
||||
"@types/tmp": "0.1.0",
|
||||
"@types/uuid": "3.4.4",
|
||||
"@types/uuid": "3.4.5",
|
||||
"@types/web-push": "3.3.0",
|
||||
"@types/webpack": "4.4.29",
|
||||
"@types/webpack": "4.4.34",
|
||||
"@types/webpack-stream": "3.2.10",
|
||||
"@types/websocket": "0.0.40",
|
||||
"@types/ws": "6.0.1",
|
||||
"animejs": "3.0.1",
|
||||
"apexcharts": "3.8.0",
|
||||
"apexcharts": "3.8.1",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autosize": "4.0.2",
|
||||
"autwh": "0.1.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bootstrap": "4.3.1",
|
||||
"bootstrap-vue": "2.0.0-rc.13",
|
||||
"bull": "3.10.0",
|
||||
"cafy": "15.1.1",
|
||||
"cbor": "4.1.5",
|
||||
"chai": "4.2.0",
|
||||
"chalk": "2.4.2",
|
||||
"cli-highlight": "2.1.1",
|
||||
"commander": "2.20.0",
|
||||
"content-disposition": "0.5.3",
|
||||
"crc-32": "1.2.0",
|
||||
"css-loader": "2.1.1",
|
||||
"css-loader": "3.0.0",
|
||||
"cssnano": "4.1.10",
|
||||
"dateformat": "3.0.3",
|
||||
"deep-equal": "1.0.1",
|
||||
"diskusage": "1.1.1",
|
||||
"diskusage": "1.1.2",
|
||||
"double-ended-queue": "2.1.0-0",
|
||||
"emojilib": "2.4.0",
|
||||
"eslint": "5.16.0",
|
||||
"eslint-plugin-vue": "5.2.2",
|
||||
"eventemitter3": "3.1.2",
|
||||
"feed": "2.0.4",
|
||||
"file-type": "10.11.0",
|
||||
"eslint": "6.0.1",
|
||||
"eslint-plugin-vue": "5.2.3",
|
||||
"eventemitter3": "4.0.0",
|
||||
"feed": "3.0.0",
|
||||
"file-type": "12.0.0",
|
||||
"fuckadblock": "3.2.1",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-cssnano": "2.1.3",
|
||||
"gulp-imagemin": "5.0.3",
|
||||
"gulp-imagemin": "6.0.0",
|
||||
"gulp-mocha": "6.0.0",
|
||||
"gulp-rename": "1.4.0",
|
||||
"gulp-replace": "1.0.0",
|
||||
|
@ -147,7 +151,8 @@
|
|||
"js-yaml": "3.13.1",
|
||||
"jsdom": "15.1.1",
|
||||
"json5": "2.1.0",
|
||||
"json5-loader": "2.0.0",
|
||||
"json5-loader": "3.0.0",
|
||||
"jsrsasign": "8.0.12",
|
||||
"katex": "0.10.2",
|
||||
"koa": "2.7.0",
|
||||
"koa-bodyparser": "4.2.1",
|
||||
|
@ -163,14 +168,14 @@
|
|||
"koa-views": "6.2.0",
|
||||
"langmap": "0.0.16",
|
||||
"loader-utils": "1.2.3",
|
||||
"lolex": "3.1.0",
|
||||
"lolex": "4.1.0",
|
||||
"lookup-dns-cache": "2.1.0",
|
||||
"minio": "7.0.10",
|
||||
"mocha": "6.1.4",
|
||||
"moji": "0.5.1",
|
||||
"moment": "2.24.0",
|
||||
"ms": "2.1.2",
|
||||
"nested-property": "0.0.7",
|
||||
"nested-property": "1.0.1",
|
||||
"node-fetch": "2.6.0",
|
||||
"nodemailer": "6.2.1",
|
||||
"nprogress": "0.2.0",
|
||||
|
@ -186,7 +191,7 @@
|
|||
"promise-any": "0.2.0",
|
||||
"promise-limit": "2.7.0",
|
||||
"promise-sequential": "1.1.1",
|
||||
"pug": "2.0.3",
|
||||
"pug": "2.0.4",
|
||||
"punycode": "2.1.1",
|
||||
"pureimage": "0.1.6",
|
||||
"qrcode": "1.3.3",
|
||||
|
@ -210,12 +215,12 @@
|
|||
"showdown": "1.9.0",
|
||||
"showdown-highlightjs-extension": "0.1.2",
|
||||
"speakeasy": "2.0.0",
|
||||
"stringz": "1.0.0",
|
||||
"stringz": "2.0.0",
|
||||
"style-loader": "0.23.1",
|
||||
"stylus": "0.54.5",
|
||||
"stylus-loader": "3.0.2",
|
||||
"summaly": "2.3.0",
|
||||
"systeminformation": "4.11.1",
|
||||
"systeminformation": "4.13.1",
|
||||
"syuilo-password-strength": "0.0.1",
|
||||
"terser-webpack-plugin": "1.3.0",
|
||||
"textarea-caret": "3.1.0",
|
||||
|
@ -223,14 +228,13 @@
|
|||
"tmp": "0.1.0",
|
||||
"ts-loader": "5.3.3",
|
||||
"ts-node": "7.0.1",
|
||||
"tslint": "5.15.0",
|
||||
"tslint": "5.18.0",
|
||||
"tslint-sonarts": "1.9.0",
|
||||
"typeorm": "0.2.16-rc.1",
|
||||
"typescript": "3.3.3333",
|
||||
"typescript-eslint-parser": "22.0.0",
|
||||
"typeorm": "0.2.18",
|
||||
"typescript": "3.5.2",
|
||||
"uglify-es": "3.3.9",
|
||||
"ulid": "2.3.0",
|
||||
"url-loader": "1.1.2",
|
||||
"url-loader": "2.0.1",
|
||||
"uuid": "3.3.2",
|
||||
"v-animate-css": "0.0.3",
|
||||
"v-debounce": "0.1.2",
|
||||
|
@ -238,7 +242,7 @@
|
|||
"vue": "2.6.10",
|
||||
"vue-color": "2.7.0",
|
||||
"vue-content-loading": "1.6.0",
|
||||
"vue-cropperjs": "3.0.0",
|
||||
"vue-cropperjs": "4.0.0",
|
||||
"vue-i18n": "8.11.2",
|
||||
"vue-js-modal": "1.3.31",
|
||||
"vue-json-pretty": "1.6.0",
|
||||
|
@ -248,17 +252,17 @@
|
|||
"vue-router": "3.0.6",
|
||||
"vue-sequential-entrance": "1.1.3",
|
||||
"vue-style-loader": "4.1.2",
|
||||
"vue-svg-inline-loader": "1.2.15",
|
||||
"vue-svg-inline-loader": "1.2.16",
|
||||
"vue-template-compiler": "2.6.10",
|
||||
"vuedraggable": "2.21.0",
|
||||
"vuedraggable": "2.23.0",
|
||||
"vuewordcloud": "18.7.11",
|
||||
"vuex": "3.1.1",
|
||||
"vuex-persistedstate": "2.5.4",
|
||||
"web-push": "3.3.5",
|
||||
"webpack": "4.34.0",
|
||||
"webpack-cli": "3.3.4",
|
||||
"webpack": "4.35.2",
|
||||
"webpack-cli": "3.3.5",
|
||||
"websocket": "1.0.28",
|
||||
"ws": "7.0.0",
|
||||
"ws": "7.0.1",
|
||||
"xev": "2.0.1"
|
||||
}
|
||||
}
|
||||
|
|
803
src/@types/jsrsasign.d.ts
vendored
Normal file
803
src/@types/jsrsasign.d.ts
vendored
Normal file
|
@ -0,0 +1,803 @@
|
|||
// Attention: Partial Type Definition
|
||||
|
||||
declare module 'jsrsasign' {
|
||||
//// HELPER TYPES
|
||||
|
||||
/**
|
||||
* Attention: The value might be changed by the function.
|
||||
*/
|
||||
type Mutable<T> = T;
|
||||
|
||||
/**
|
||||
* Deprecated: The function might be deleted in future release.
|
||||
*/
|
||||
type Deprecated<T> = T;
|
||||
|
||||
//// COMMON TYPES
|
||||
|
||||
/**
|
||||
* byte number
|
||||
*/
|
||||
type ByteNumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255;
|
||||
|
||||
/**
|
||||
* hexadecimal string /[0-9A-F]/
|
||||
*/
|
||||
type HexString = string;
|
||||
|
||||
/**
|
||||
* binary string /[01]/
|
||||
*/
|
||||
type BinString = string;
|
||||
|
||||
/**
|
||||
* base64 string /[A-Za-z0-9+/]=+/
|
||||
*/
|
||||
type Base64String = string;
|
||||
|
||||
/**
|
||||
* base64 URL encoded string /[A-Za-z0-9_-]/
|
||||
*/
|
||||
type Base64URLString = string;
|
||||
|
||||
/**
|
||||
* time value (ex. "151231235959Z")
|
||||
*/
|
||||
type TimeValue = string;
|
||||
|
||||
/**
|
||||
* OID string (ex. '1.2.3.4.567')
|
||||
*/
|
||||
type OID = string;
|
||||
|
||||
/**
|
||||
* OID name
|
||||
*/
|
||||
type OIDName = string;
|
||||
|
||||
/**
|
||||
* PEM formatted string
|
||||
*/
|
||||
type PEM = string;
|
||||
|
||||
//// ASN1 TYPES
|
||||
|
||||
class ASN1Object {
|
||||
public isModified: boolean;
|
||||
|
||||
public hTLV: ASN1TLV;
|
||||
|
||||
public hT: ASN1T;
|
||||
|
||||
public hL: ASN1L;
|
||||
|
||||
public hV: ASN1V;
|
||||
|
||||
public getLengthHexFromValue(): HexString;
|
||||
|
||||
public getEncodedHex(): ASN1TLV;
|
||||
|
||||
public getValueHex(): ASN1V;
|
||||
|
||||
public getFreshValueHex(): ASN1V;
|
||||
}
|
||||
|
||||
class DERAbstractStructured extends ASN1Object {
|
||||
constructor(params?: Partial<Record<'array', ASN1Object[]>>);
|
||||
|
||||
public setByASN1ObjectArray(asn1ObjectArray: ASN1Object[]): void;
|
||||
|
||||
public appendASN1Object(asn1Object: ASN1Object): void;
|
||||
}
|
||||
|
||||
class DERSequence extends DERAbstractStructured {
|
||||
constructor(params?: Partial<Record<'array', ASN1Object[]>>);
|
||||
|
||||
public getFreshValueHex(): ASN1V;
|
||||
}
|
||||
|
||||
//// ASN1HEX TYPES
|
||||
|
||||
/**
|
||||
* ASN.1 DER encoded data (hexadecimal string)
|
||||
*/
|
||||
type ASN1S = HexString;
|
||||
|
||||
/**
|
||||
* index of something
|
||||
*/
|
||||
type Idx<T extends { [idx: string]: unknown } | { [idx: number]: unknown }> = ASN1S extends { [idx: string]: unknown } ? string : ASN1S extends { [idx: number]: unknown } ? number : never;
|
||||
|
||||
/**
|
||||
* byte length of something
|
||||
*/
|
||||
type ByteLength<T extends { length: unknown }> = T['length'];
|
||||
|
||||
/**
|
||||
* ASN.1 L(length) (hexadecimal string)
|
||||
*/
|
||||
type ASN1L = HexString;
|
||||
|
||||
/**
|
||||
* ASN.1 T(tag) (hexadecimal string)
|
||||
*/
|
||||
type ASN1T = HexString;
|
||||
|
||||
/**
|
||||
* ASN.1 V(value) (hexadecimal string)
|
||||
*/
|
||||
type ASN1V = HexString;
|
||||
|
||||
/**
|
||||
* ASN.1 TLV (hexadecimal string)
|
||||
*/
|
||||
type ASN1TLV = HexString;
|
||||
|
||||
/**
|
||||
* ASN.1 object string
|
||||
*/
|
||||
type ASN1ObjectString = string;
|
||||
|
||||
/**
|
||||
* nth
|
||||
*/
|
||||
type Nth = number;
|
||||
|
||||
/**
|
||||
* ASN.1 DER encoded OID value (hexadecimal string)
|
||||
*/
|
||||
type ASN1OIDV = HexString;
|
||||
|
||||
class ASN1HEX {
|
||||
public static getLblen(s: ASN1S, idx: Idx<ASN1S>): ByteLength<ASN1L>;
|
||||
|
||||
public static getL(s: ASN1S, idx: Idx<ASN1S>): ASN1L;
|
||||
|
||||
public static getVblen(s: ASN1S, idx: Idx<ASN1S>): ByteLength<ASN1V>;
|
||||
|
||||
public static getVidx(s: ASN1S, idx: Idx<ASN1S>): Idx<ASN1V>;
|
||||
|
||||
public static getV(s: ASN1S, idx: Idx<ASN1S>): ASN1V;
|
||||
|
||||
public static getTLV(s: ASN1S, idx: Idx<ASN1S>): ASN1TLV;
|
||||
|
||||
public static getNextSiblingIdx(s: ASN1S, idx: Idx<ASN1S>): Idx<ASN1ObjectString>;
|
||||
|
||||
public static getChildIdx(h: ASN1S, pos: Idx<ASN1S>): Idx<ASN1ObjectString>[];
|
||||
|
||||
public static getNthChildIdx(h: ASN1S, idx: Idx<ASN1S>, nth: Nth): Idx<ASN1ObjectString>;
|
||||
|
||||
public static getIdxbyList(h: ASN1S, currentIndex: Idx<ASN1ObjectString>, nthList: Mutable<Nth[]>, checkingTag?: string): Idx<Mutable<Nth[]>>;
|
||||
|
||||
public static getTLVbyList(h: ASN1S, currentIndex: Idx<ASN1ObjectString>, nthList: Mutable<Nth[]>, checkingTag?: string): ASN1TLV;
|
||||
|
||||
public static getVbyList(h: ASN1S, currentIndex: Idx<ASN1ObjectString>, nthList: Mutable<Nth[]>, checkingTag?: string, removeUnusedbits?: boolean): ASN1V;
|
||||
|
||||
public static hextooidstr(hex: ASN1OIDV): OID;
|
||||
|
||||
public static dump(hexOrObj: ASN1S | ASN1Object, flags?: Record<string, unknown>, idx?: Idx<ASN1S>, indent?: string): string;
|
||||
|
||||
public static isASN1HEX(hex: string): hex is HexString;
|
||||
|
||||
public static oidname(oidDotOrHex: OID | ASN1OIDV): OIDName;
|
||||
}
|
||||
|
||||
//// BIG INTEGER TYPES (PARTIAL)
|
||||
|
||||
class BigInteger {
|
||||
constructor(a: null);
|
||||
|
||||
constructor(a: number, b: SecureRandom);
|
||||
|
||||
constructor(a: number, b: number, c: SecureRandom);
|
||||
|
||||
constructor(a: unknown);
|
||||
|
||||
constructor(a: string, b: number);
|
||||
|
||||
public am(i: number, x: number, w: number, j: number, c: number, n: number): number;
|
||||
|
||||
public DB: number;
|
||||
|
||||
public DM: number;
|
||||
|
||||
public DV: number;
|
||||
|
||||
public FV: number;
|
||||
|
||||
public F1: number;
|
||||
|
||||
public F2: number;
|
||||
|
||||
protected copyTo(r: Mutable<BigInteger>): void;
|
||||
|
||||
protected fromInt(x: number): void;
|
||||
|
||||
protected fromString(s: string, b: number): void;
|
||||
|
||||
protected clamp(): void;
|
||||
|
||||
public toString(b: number): string;
|
||||
|
||||
public negate(): BigInteger;
|
||||
|
||||
public abs(): BigInteger;
|
||||
|
||||
public compareTo(a: BigInteger): number;
|
||||
|
||||
public bitLength(): number;
|
||||
|
||||
protected dlShiftTo(n: number, r: Mutable<BigInteger>): void;
|
||||
|
||||
protected drShiftTo(n: number, r: Mutable<BigInteger>): void;
|
||||
|
||||
protected lShiftTo(n: number, r: Mutable<BigInteger>): void;
|
||||
|
||||
protected rShiftTo(n: number, r: Mutable<BigInteger>): void;
|
||||
|
||||
protected subTo(a: BigInteger, r: Mutable<BigInteger>): void;
|
||||
|
||||
protected multiplyTo(a: BigInteger, r: Mutable<BigInteger>): void;
|
||||
|
||||
protected squareTo(r: Mutable<BigInteger>): void;
|
||||
|
||||
protected divRemTo(m: BigInteger, q: Mutable<BigInteger>, r: Mutable<BigInteger>): void;
|
||||
|
||||
public mod(a: BigInteger): BigInteger;
|
||||
|
||||
protected invDigit(): number;
|
||||
|
||||
protected isEven(): boolean;
|
||||
|
||||
protected exp(e: number, z: Classic | Montgomery): BigInteger;
|
||||
|
||||
public modPowInt(e: number, m: BigInteger): BigInteger;
|
||||
|
||||
public static ZERO: BigInteger;
|
||||
|
||||
public static ONE: BigInteger;
|
||||
}
|
||||
|
||||
class Classic {
|
||||
constructor(m: BigInteger);
|
||||
|
||||
public convert(x: BigInteger): BigInteger;
|
||||
|
||||
public revert(x: BigInteger): BigInteger;
|
||||
|
||||
public reduce(x: Mutable<BigInteger>): void;
|
||||
|
||||
public mulTo(x: BigInteger, r: Mutable<BigInteger>): void;
|
||||
|
||||
public sqrTo(x: BigInteger, y: BigInteger, r: Mutable<BigInteger>): void;
|
||||
}
|
||||
|
||||
class Montgomery {
|
||||
constructor(m: BigInteger);
|
||||
|
||||
public convert(x: BigInteger): BigInteger;
|
||||
|
||||
public revert(x: BigInteger): BigInteger;
|
||||
|
||||
public reduce(x: Mutable<BigInteger>): void;
|
||||
|
||||
public mulTo(x: BigInteger, r: Mutable<BigInteger>): void;
|
||||
|
||||
public sqrTo(x: BigInteger, y: BigInteger, r: Mutable<BigInteger>): void;
|
||||
}
|
||||
|
||||
//// KEYUTIL TYPES
|
||||
|
||||
type DecryptAES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
|
||||
|
||||
type Decrypt3DES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
|
||||
|
||||
type DecryptDES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
|
||||
|
||||
type EncryptAES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
|
||||
|
||||
type Encrypt3DES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
|
||||
|
||||
type EncryptDES = (dataHex: HexString, keyHex: HexString, ivHex: HexString) => HexString;
|
||||
|
||||
type AlgList = {
|
||||
'AES-256-CBC': { 'proc': DecryptAES; 'eproc': EncryptAES; keylen: 32; ivlen: 16; };
|
||||
'AES-192-CBC': { 'proc': DecryptAES; 'eproc': EncryptAES; keylen: 24; ivlen: 16; };
|
||||
'AES-128-CBC': { 'proc': DecryptAES; 'eproc': EncryptAES; keylen: 16; ivlen: 16; };
|
||||
'DES-EDE3-CBC': { 'proc': Decrypt3DES; 'eproc': Encrypt3DES; keylen: 24; ivlen: 8; };
|
||||
'DES-CBC': { 'proc': DecryptDES; 'eproc': EncryptDES; keylen: 8; ivlen: 8; };
|
||||
};
|
||||
|
||||
type AlgName = keyof AlgList;
|
||||
|
||||
type PEMHeadAlgName = 'RSA' | 'EC' | 'DSA';
|
||||
|
||||
type GetKeyRSAParam = RSAKey | {
|
||||
n: BigInteger;
|
||||
e: number;
|
||||
} | Record<'n' | 'e', HexString> | Record<'n' | 'e', HexString> & Record<'d' | 'p' | 'q' | 'dp' | 'dq' | 'co', HexString | null> | {
|
||||
n: BigInteger;
|
||||
e: number;
|
||||
d: BigInteger;
|
||||
} | {
|
||||
kty: 'RSA';
|
||||
} & Record<'n' | 'e', Base64URLString> | {
|
||||
kty: 'RSA';
|
||||
} & Record<'n' | 'e' | 'd' | 'p' | 'q' | 'dp' | 'dq' | 'qi', Base64URLString> | {
|
||||
kty: 'RSA';
|
||||
} & Record<'n' | 'e' | 'd', Base64URLString>;
|
||||
|
||||
type GetKeyECDSAParam = KJUR.crypto.ECDSA | {
|
||||
curve: KJUR.crypto.CurveName;
|
||||
xy: HexString;
|
||||
} | {
|
||||
curve: KJUR.crypto.CurveName;
|
||||
d: HexString;
|
||||
} | {
|
||||
kty: 'EC';
|
||||
crv: KJUR.crypto.CurveName;
|
||||
x: Base64URLString;
|
||||
y: Base64URLString;
|
||||
} | {
|
||||
kty: 'EC';
|
||||
crv: KJUR.crypto.CurveName;
|
||||
x: Base64URLString;
|
||||
y: Base64URLString;
|
||||
d: Base64URLString;
|
||||
};
|
||||
|
||||
type GetKeyDSAParam = KJUR.crypto.DSA | Record<'p' | 'q' | 'g', BigInteger> & Record<'y', BigInteger | null> | Record<'p' | 'q' | 'g' | 'x', BigInteger> & Record<'y', BigInteger | null>;
|
||||
|
||||
type GetKeyParam = GetKeyRSAParam | GetKeyECDSAParam | GetKeyDSAParam | string;
|
||||
|
||||
class KEYUTIL {
|
||||
public version: '1.0.0';
|
||||
|
||||
public parsePKCS5PEM(sPKCS5PEM: PEM): Partial<Record<'type' | 's', string>> & (Record<'cipher' | 'ivsalt', string> | Record<'cipher' | 'ivsalt', undefined>);
|
||||
|
||||
public getKeyAndUnusedIvByPasscodeAndIvsalt(algName: AlgName, passcode: string, ivsaltHex: HexString): Record<'keyhex' | 'ivhex', HexString>;
|
||||
|
||||
public decryptKeyB64(privateKeyB64: Base64String, sharedKeyAlgName: AlgName, sharedKeyHex: HexString, ivsaltHex: HexString): Base64String;
|
||||
|
||||
public getDecryptedKeyHex(sEncryptedPEM: PEM, passcode: string): HexString;
|
||||
|
||||
public getEncryptedPKCS5PEMFromPrvKeyHex(pemHeadAlg: PEMHeadAlgName, hPrvKey: string, passcode: string, sharedKeyAlgName?: AlgName | null, ivsaltHex?: HexString | null): PEM;
|
||||
|
||||
public parseHexOfEncryptedPKCS8(sHEX: HexString): {
|
||||
ciphertext: ASN1V;
|
||||
encryptionSchemeAlg: 'TripleDES';
|
||||
encryptionSchemeIV: ASN1V;
|
||||
pbkdf2Salt: ASN1V;
|
||||
pbkdf2Iter: number;
|
||||
};
|
||||
|
||||
public getPBKDF2KeyHexFromParam(info: ReturnType<this['parseHexOfEncryptedPKCS8']>, passcode: string): HexString;
|
||||
|
||||
private _getPlainPKCS8HexFromEncryptedPKCS8PEM(pkcs8PEM: PEM, passcode: string): HexString;
|
||||
|
||||
public getKeyFromEncryptedPKCS8PEM(prvKeyHex: HexString): ReturnType<this['getKeyFromPlainPrivatePKCS8Hex']>;
|
||||
|
||||
public parsePlainPrivatePKCS8Hex(pkcs8PrvHex: HexString): {
|
||||
algparam: ASN1V | null;
|
||||
algoid: ASN1V;
|
||||
keyidx: Idx<ASN1V>;
|
||||
};
|
||||
|
||||
public getKeyFromPlainPrivatePKCS8PEM(prvKeyHex: HexString): ReturnType<this['getKeyFromPlainPrivatePKCS8Hex']>;
|
||||
|
||||
public getKeyFromPlainPrivatePKCS8Hex(prvKeyHex: HexString): RSAKey | KJUR.crypto.DSA | KJUR.crypto.ECDSA;
|
||||
|
||||
private _getKeyFromPublicPKCS8Hex(h: HexString): RSAKey | KJUR.crypto.DSA | KJUR.crypto.ECDSA;
|
||||
|
||||
public parsePublicRawRSAKeyHex(pubRawRSAHex: HexString): Record<'n' | 'e', ASN1V>;
|
||||
|
||||
public parsePublicPKCS8Hex(pkcs8PubHex: HexString): {
|
||||
algparam: ASN1V | Record<'p' | 'q' | 'g', ASN1V> | null;
|
||||
algoid: ASN1V;
|
||||
key: ASN1V;
|
||||
};
|
||||
|
||||
public static getKey(param: GetKeyRSAParam): RSAKey;
|
||||
|
||||
public static getKey(param: GetKeyECDSAParam): KJUR.crypto.ECDSA;
|
||||
|
||||
public static getKey(param: GetKeyDSAParam): KJUR.crypto.DSA;
|
||||
|
||||
public static getKey(param: string, passcode?: string, hextype?: string): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
|
||||
|
||||
public static generateKeypair(alg: 'RSA', keylen: number): Record<'prvKeyObj' | 'pubKeyObj', RSAKey>;
|
||||
|
||||
public static generateKeypair(alg: 'EC', curve: KJUR.crypto.CurveName): Record<'prvKeyObj' | 'pubKeyObj', KJUR.crypto.ECDSA>;
|
||||
|
||||
public static getPEM(keyObjOrHex: RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA, formatType?: 'PKCS1PRV' | 'PKCS5PRV' | 'PKCS8PRV', passwd?: string, encAlg?: 'DES-CBC' | 'DES-EDE3-CBC' | 'AES-128-CBC' | 'AES-192-CBC' | 'AES-256-CBC', hexType?: string, ivsaltHex?: HexString): object; // To Do
|
||||
|
||||
public static getKeyFromCSRPEM(csrPEM: PEM): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
|
||||
|
||||
public static getKeyFromCSRHex(csrHex: HexString): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
|
||||
|
||||
public static parseCSRHex(csrHex: HexString): Record<'p8pubkeyhex', ASN1TLV>;
|
||||
|
||||
public static getJWKFromKey(keyObj: RSAKey): {
|
||||
kty: 'RSA';
|
||||
} & Record<'n' | 'e' | 'd' | 'p' | 'q' | 'dp' | 'dq' | 'qi', Base64URLString> | {
|
||||
kty: 'RSA';
|
||||
} & Record<'n' | 'e', Base64URLString>;
|
||||
|
||||
public static getJWKFromKey(keyObj: KJUR.crypto.ECDSA): {
|
||||
kty: 'EC';
|
||||
crv: KJUR.crypto.CurveName;
|
||||
x: Base64URLString;
|
||||
y: Base64URLString;
|
||||
d: Base64URLString;
|
||||
} | {
|
||||
kty: 'EC';
|
||||
crv: KJUR.crypto.CurveName;
|
||||
x: Base64URLString;
|
||||
y: Base64URLString;
|
||||
};
|
||||
}
|
||||
|
||||
//// KJUR NAMESPACE (PARTIAL)
|
||||
|
||||
namespace KJUR {
|
||||
namespace crypto {
|
||||
type CurveName = 'secp128r1' | 'secp160k1' | 'secp160r1' | 'secp192k1' | 'secp192r1' | 'secp224r1' | 'secp256k1' | 'secp256r1' | 'secp384r1' | 'secp521r1';
|
||||
|
||||
class DSA {
|
||||
public p: BigInteger | null;
|
||||
|
||||
public q: BigInteger | null;
|
||||
|
||||
public g: BigInteger | null;
|
||||
|
||||
public y: BigInteger | null;
|
||||
|
||||
public x: BigInteger | null;
|
||||
|
||||
public type: 'DSA';
|
||||
|
||||
public isPrivate: boolean;
|
||||
|
||||
public isPublic: boolean;
|
||||
|
||||
public setPrivate(p: BigInteger, q: BigInteger, g: BigInteger, y: BigInteger | null, x: BigInteger): void;
|
||||
|
||||
public setPrivateHex(hP: HexString, hQ: HexString, hG: HexString, hY: HexString | null, hX: HexString): void;
|
||||
|
||||
public setPublic(p: BigInteger, q: BigInteger, g: BigInteger, y: BigInteger): void;
|
||||
|
||||
public setPublicHex(hP: HexString, hQ: HexString, hG: HexString, hY: HexString): void;
|
||||
|
||||
public signWithMessageHash(sHashHex: HexString): HexString;
|
||||
|
||||
public verifyWithMessageHash(sHashHex: HexString, hSigVal: HexString): boolean;
|
||||
|
||||
public parseASN1Signature(hSigVal: HexString): [BigInteger, BigInteger];
|
||||
|
||||
public readPKCS5PrvKeyHex(h: HexString): void;
|
||||
|
||||
public readPKCS8PrvKeyHex(h: HexString): void;
|
||||
|
||||
public readPKCS8PubKeyHex(h: HexString): void;
|
||||
|
||||
public readCertPubKeyHex(h: HexString, nthPKI: number): void;
|
||||
}
|
||||
|
||||
class ECDSA {
|
||||
constructor(params?: {
|
||||
curve?: CurveName;
|
||||
prv?: HexString;
|
||||
pub?: HexString;
|
||||
});
|
||||
|
||||
public p: BigInteger | null;
|
||||
|
||||
public q: BigInteger | null;
|
||||
|
||||
public g: BigInteger | null;
|
||||
|
||||
public y: BigInteger | null;
|
||||
|
||||
public x: BigInteger | null;
|
||||
|
||||
public type: 'EC';
|
||||
|
||||
public isPrivate: boolean;
|
||||
|
||||
public isPublic: boolean;
|
||||
|
||||
public getBigRandom(limit: BigInteger): BigInteger;
|
||||
|
||||
public setNamedCurve(curveName: CurveName): void;
|
||||
|
||||
public setPrivateKeyHex(prvKeyHex: HexString): void;
|
||||
|
||||
public setPublicKeyHex(pubKeyHex: HexString): void;
|
||||
|
||||
public getPublicKeyXYHex(): Record<'x' | 'y', HexString>;
|
||||
|
||||
public getShortNISTPCurveName(): 'P-256' | 'P-384' | null;
|
||||
|
||||
public generateKeyPairHex(): Record<'ecprvhex' | 'ecpubhex', HexString>;
|
||||
|
||||
public signWithMessageHash(hashHex: HexString): HexString;
|
||||
|
||||
public signHex(hashHex: HexString, privHex: HexString): HexString;
|
||||
|
||||
public verifyWithMessageHash(sHashHex: HexString, hSigVal: HexString): boolean;
|
||||
|
||||
public parseASN1Signature(hSigVal: HexString): [BigInteger, BigInteger];
|
||||
|
||||
public readPKCS5PrvKeyHex(h: HexString): void;
|
||||
|
||||
public readPKCS8PrvKeyHex(h: HexString): void;
|
||||
|
||||
public readPKCS8PubKeyHex(h: HexString): void;
|
||||
|
||||
public readCertPubKeyHex(h: HexString, nthPKI: number): void;
|
||||
|
||||
public static parseSigHex(sigHex: HexString): Record<'r' | 's', BigInteger>;
|
||||
|
||||
public static parseSigHexInHexRS(sigHex: HexString): Record<'r' | 's', ASN1V>;
|
||||
|
||||
public static asn1SigToConcatSig(asn1Sig: HexString): HexString;
|
||||
|
||||
public static concatSigToASN1Sig(concatSig: HexString): ASN1TLV;
|
||||
|
||||
public static hexRSSigToASN1Sig(hR: HexString, hS: HexString): ASN1TLV;
|
||||
|
||||
public static biRSSigToASN1Sig(biR: BigInteger, biS: BigInteger): ASN1TLV;
|
||||
|
||||
public static getName(s: CurveName | HexString): 'secp256r1' | 'secp256k1' | 'secp384r1' | null;
|
||||
}
|
||||
|
||||
class Signature {
|
||||
constructor(params?: ({
|
||||
alg: string;
|
||||
prov?: string;
|
||||
} | {}) & ({
|
||||
psssaltlen: number;
|
||||
} | {}) & ({
|
||||
prvkeypem: PEM;
|
||||
prvkeypas?: never;
|
||||
} | {}));
|
||||
|
||||
private _setAlgNames(): void;
|
||||
|
||||
private _zeroPaddingOfSignature(hex: HexString, bitLength: number): HexString;
|
||||
|
||||
public setAlgAndProvider(alg: string, prov: string): void;
|
||||
|
||||
public init(key: GetKeyParam, pass?: string): void;
|
||||
|
||||
public updateString(str: string): void;
|
||||
|
||||
public updateHex(hex: HexString): void;
|
||||
|
||||
public sign(): HexString;
|
||||
|
||||
public signString(str: string): HexString;
|
||||
|
||||
public signHex(hex: HexString): HexString;
|
||||
|
||||
public verify(hSigVal: string): boolean | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// RSAKEY TYPES
|
||||
|
||||
class RSAKey {
|
||||
public n: BigInteger | null;
|
||||
|
||||
public e: number;
|
||||
|
||||
public d: BigInteger | null;
|
||||
|
||||
public p: BigInteger | null;
|
||||
|
||||
public q: BigInteger | null;
|
||||
|
||||
public dmp1: BigInteger | null;
|
||||
|
||||
public dmq1: BigInteger | null;
|
||||
|
||||
public coeff: BigInteger | null;
|
||||
|
||||
public type: 'RSA';
|
||||
|
||||
public isPrivate?: boolean;
|
||||
|
||||
public isPublic?: boolean;
|
||||
|
||||
//// RSA PUBLIC
|
||||
|
||||
protected doPublic(x: BigInteger): BigInteger;
|
||||
|
||||
public setPublic(N: BigInteger, E: number): void;
|
||||
|
||||
public setPublic(N: HexString, E: HexString): void;
|
||||
|
||||
public encrypt(text: string): HexString | null;
|
||||
|
||||
public encryptOAEP(text: string, hash?: string, hashLen?: number): HexString | null;
|
||||
|
||||
public encryptOAEP(text: string, hash?: (s: string) => string, hashLen?: number): HexString | null;
|
||||
|
||||
//// RSA PRIVATE
|
||||
|
||||
protected doPrivate(x: BigInteger): BigInteger;
|
||||
|
||||
public setPrivate(N: BigInteger, E: number, D: BigInteger): void;
|
||||
|
||||
public setPrivate(N: HexString, E: HexString, D: HexString): void;
|
||||
|
||||
public setPrivateEx(N: HexString, E: HexString, D?: HexString | null, P?: HexString | null, Q?: HexString | null, DP?: HexString | null, DQ?: HexString | null, C?: HexString | null): void;
|
||||
|
||||
public generate(B: number, E: HexString): void;
|
||||
|
||||
public decrypt(ctext: HexString): string;
|
||||
|
||||
public decryptOAEP(ctext: HexString, hash?: string, hashLen?: number): string | null;
|
||||
|
||||
public encryptOAEP(ctext: HexString, hash?: (s: string) => string, hashLen?: number): string | null;
|
||||
|
||||
//// RSA PEM
|
||||
|
||||
public getPosArrayOfChildrenFromHex(hPrivateKey: PEM): Idx<ASN1ObjectString>[];
|
||||
|
||||
public getHexValueArrayOfChildrenFromHex(hPrivateKey: PEM): Idx<ASN1ObjectString>[];
|
||||
|
||||
public readPrivateKeyFromPEMString(keyPEM: PEM): void;
|
||||
|
||||
public readPKCS5PrvKeyHex(h: HexString): void;
|
||||
|
||||
public readPKCS8PrvKeyHex(h: HexString): void;
|
||||
|
||||
public readPKCS5PubKeyHex(h: HexString): void;
|
||||
|
||||
public readPKCS8PubKeyHex(h: HexString): void;
|
||||
|
||||
public readCertPubKeyHex(h: HexString, nthPKI: Nth): void;
|
||||
|
||||
//// RSA SIGN
|
||||
|
||||
public sign(s: string, hashAlg: string): HexString;
|
||||
|
||||
public signWithMessageHash(sHashHex: HexString, hashAlg: string): HexString;
|
||||
|
||||
public signPSS(s: string, hashAlg: string, sLen: number): HexString;
|
||||
|
||||
public signWithMessageHashPSS(hHash: HexString, hashAlg: string, sLen: number): HexString;
|
||||
|
||||
public verify(sMsg: string, hSig: HexString): boolean | 0;
|
||||
|
||||
public verifyWithMessageHash(sHashHex: HexString, hSig: HexString): boolean | 0;
|
||||
|
||||
public verifyPSS(sMsg: string, hSig: HexString, hashAlg: string, sLen: number): boolean;
|
||||
|
||||
public verifyWithMessageHashPSS(hHash: HexString, hSig: HexString, hashAlg: string, sLen: number): boolean;
|
||||
|
||||
public static SALT_LEN_HLEN: -1;
|
||||
|
||||
public static SALT_LEN_MAX: -2;
|
||||
|
||||
public static SALT_LEN_RECOVER: -2;
|
||||
}
|
||||
|
||||
/// RNG TYPES
|
||||
class SecureRandom {
|
||||
public nextBytes(ba: Mutable<ByteNumber[]>): void;
|
||||
}
|
||||
|
||||
//// X509 TYPES
|
||||
|
||||
type ExtInfo = {
|
||||
critical: boolean;
|
||||
oid: OID;
|
||||
vidx: Idx<ASN1V>;
|
||||
};
|
||||
|
||||
type ExtAIAInfo = Record<'ocsp' | 'caissuer', string>;
|
||||
|
||||
type ExtCertificatePolicy = {
|
||||
id: OIDName;
|
||||
} & Partial<{
|
||||
cps: string;
|
||||
} | {
|
||||
unotice: string;
|
||||
}>;
|
||||
|
||||
class X509 {
|
||||
public hex: HexString | null;
|
||||
|
||||
public version: number;
|
||||
|
||||
public foffset: number;
|
||||
|
||||
public aExtInfo: null;
|
||||
|
||||
public getVersion(): number;
|
||||
|
||||
public getSerialNumberHex(): ASN1V;
|
||||
|
||||
public getSignatureAlgorithmField(): OIDName;
|
||||
|
||||
public getIssuerHex(): ASN1TLV;
|
||||
|
||||
public getIssuerString(): HexString;
|
||||
|
||||
public getSubjectHex(): ASN1TLV;
|
||||
|
||||
public getSubjectString(): HexString;
|
||||
|
||||
public getNotBefore(): TimeValue;
|
||||
|
||||
public getNotAfter(): TimeValue;
|
||||
|
||||
public getPublicKeyHex(): ASN1TLV;
|
||||
|
||||
public getPublicKeyIdx(): Idx<Mutable<Nth[]>>;
|
||||
|
||||
public getPublicKeyContentIdx(): Idx<Mutable<Nth[]>>;
|
||||
|
||||
public getPublicKey(): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
|
||||
|
||||
public getSignatureAlgorithmName(): OIDName;
|
||||
|
||||
public getSignatureValueHex(): ASN1V;
|
||||
|
||||
public verifySignature(pubKey: GetKeyParam): boolean | 0;
|
||||
|
||||
public parseExt(): void;
|
||||
|
||||
public getExtInfo(oidOrName: OID | string): ExtInfo | undefined;
|
||||
|
||||
public getExtBasicConstraints(): ExtInfo | {} | {
|
||||
cA: true;
|
||||
pathLen?: number;
|
||||
};
|
||||
|
||||
public getExtKeyUsageBin(): BinString;
|
||||
|
||||
public getExtKeyUsageString(): string;
|
||||
|
||||
public getExtSubjectKeyIdentifier(): ASN1V | undefined;
|
||||
|
||||
public getExtAuthorityKeyIdentifier(): {
|
||||
kid: ASN1V;
|
||||
} | undefined;
|
||||
|
||||
public getExtExtKeyUsageName(): OIDName[] | undefined;
|
||||
|
||||
public getExtSubjectAltName(): Deprecated<string[]>;
|
||||
|
||||
public getExtSubjectAltName2(): ['MAIL' | 'DNS' | 'DN' | 'URI' | 'IP', string][] | undefined;
|
||||
|
||||
public getExtCRLDistributionPointsURI(): string[] | undefined;
|
||||
|
||||
public getExtAIAInfo(): ExtAIAInfo | undefined;
|
||||
|
||||
public getExtCertificatePolicies(): ExtCertificatePolicy[] | undefined;
|
||||
|
||||
public readCertPEM(sCertPEM: PEM): void;
|
||||
|
||||
public readCertHex(sCertHex: HexString): void;
|
||||
|
||||
public getInfo(): string;
|
||||
|
||||
public static hex2dn(hex: HexString, idx?: Idx<HexString>): string;
|
||||
|
||||
public static hex2rdn(hex: HexString, idx?: Idx<HexString>): string;
|
||||
|
||||
public static hex2attrTypeValue(hex: HexString, idx?: Idx<HexString>): string;
|
||||
|
||||
public static getPublicKeyFromCertPEM(sCertPEM: PEM): RSAKey | KJUR.crypto.ECDSA | KJUR.crypto.DSA;
|
||||
|
||||
public static getPublicKeyInfoPropOfCertPEM(sCertPEM: PEM): {
|
||||
algparam: ASN1V | null;
|
||||
leyhex: ASN1V;
|
||||
algoid: ASN1V;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -79,6 +79,7 @@ export async function masterMain() {
|
|||
require('../daemons/server-stats').default();
|
||||
require('../daemons/notes-stats').default();
|
||||
require('../daemons/queue-stats').default();
|
||||
require('../daemons/janitor').default();
|
||||
}
|
||||
|
||||
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
|
||||
|
|
|
@ -5,6 +5,14 @@
|
|||
<section v-if="tables">
|
||||
<div v-for="table in Object.keys(tables)"><b>{{ table }}</b> {{ tables[table].count | number }} {{ tables[table].size | bytes }}</div>
|
||||
</section>
|
||||
<section>
|
||||
<header><fa :icon="faBroom"/> {{ $t('vacuum') }}</header>
|
||||
<ui-info>{{ $t('vacuum-info') }}</ui-info>
|
||||
<ui-switch v-model="fullVacuum">FULL</ui-switch>
|
||||
<ui-switch v-model="analyzeVacuum">ANALYZE</ui-switch>
|
||||
<ui-button @click="vacuum()"><fa :icon="faBroom"/> {{ $t('vacuum') }}</ui-button>
|
||||
<ui-info warn>{{ $t('vacuum-exclamation') }}</ui-info>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -12,7 +20,7 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../i18n';
|
||||
import { faDatabase } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faDatabase, faBroom } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('admin/views/db.vue'),
|
||||
|
@ -20,7 +28,9 @@ export default Vue.extend({
|
|||
data() {
|
||||
return {
|
||||
tables: null,
|
||||
faDatabase
|
||||
fullVacuum: true,
|
||||
analyzeVacuum: true,
|
||||
faDatabase, faBroom
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -34,6 +44,18 @@ export default Vue.extend({
|
|||
this.tables = tables;
|
||||
});
|
||||
},
|
||||
|
||||
vacuum() {
|
||||
this.$root.api('admin/vacuum', {
|
||||
full: this.fullVacuum,
|
||||
analyze: this.analyzeVacuum,
|
||||
}).then(() => {
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
splash: true
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -129,6 +129,7 @@
|
|||
<ui-input v-model="smtpPass" type="password" :with-password-toggle="true" :disabled="!enableEmail || !smtpAuth">{{ $t('smtp-pass') }}</ui-input>
|
||||
</ui-horizon-group>
|
||||
<ui-switch v-model="smtpSecure" :disabled="!enableEmail">{{ $t('smtp-secure') }}<template #desc>{{ $t('smtp-secure-info') }}</template></ui-switch>
|
||||
<ui-button @click="testEmail()">{{ $t('test-email') }}</ui-button>
|
||||
</template>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -424,6 +425,24 @@ export default Vue.extend({
|
|||
});
|
||||
},
|
||||
|
||||
async testEmail() {
|
||||
this.$root.api('admin/send-email', {
|
||||
to: this.maintainerEmail,
|
||||
subject: 'Test email',
|
||||
text: 'Yo'
|
||||
}).then(x => {
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
splash: true
|
||||
});
|
||||
}).catch(e => {
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: e
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
updateMeta() {
|
||||
this.$root.api('admin/update-meta', {
|
||||
maintainerName: this.maintainerName,
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev';
|
||||
if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth';
|
||||
if (`${url.pathname}/`.startsWith('/admin/')) app = 'admin';
|
||||
if (`${url.pathname}/`.startsWith('/test/')) app = 'test';
|
||||
//#endregion
|
||||
|
||||
// Script version
|
||||
|
|
5
src/client/app/common/scripts/2fa.ts
Normal file
5
src/client/app/common/scripts/2fa.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export function hexifyAB(buffer) {
|
||||
return Array.from(new Uint8Array(buffer))
|
||||
.map(item => item.toString(16).padStart(2, 0))
|
||||
.join('');
|
||||
}
|
|
@ -33,7 +33,7 @@
|
|||
</template>
|
||||
</ui-select>
|
||||
<ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash && (showOkButton || showCancelButton)">
|
||||
<ui-button @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user">{{ (showCancelButton || input || select || user) ? $t('@.ok') : $t('@.got-it') }}</ui-button>
|
||||
<ui-button @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user" :disabled="!canOk">{{ (showCancelButton || input || select || user) ? $t('@.ok') : $t('@.got-it') }}</ui-button>
|
||||
<ui-button @click="cancel" v-if="showCancelButton || input || select || user">{{ $t('@.cancel') }}</ui-button>
|
||||
</ui-horizon-group>
|
||||
</template>
|
||||
|
@ -99,11 +99,26 @@ export default Vue.extend({
|
|||
inputValue: this.input && this.input.default ? this.input.default : null,
|
||||
userInputValue: null,
|
||||
selectedValue: this.select ? this.select.items ? this.select.items[0].value : this.select.groupedItems[0].items[0].value : null,
|
||||
canOk: true,
|
||||
faTimesCircle, faQuestionCircle
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
userInputValue() {
|
||||
if (this.user) {
|
||||
this.$root.api('users/show', parseAcct(this.userInputValue)).then(u => {
|
||||
this.canOk = u != null;
|
||||
}).catch(() => {
|
||||
this.canOk = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.user) this.canOk = false;
|
||||
|
||||
this.$nextTick(() => {
|
||||
(this.$refs.bg as any).style.pointerEvents = 'auto';
|
||||
anime({
|
||||
|
@ -131,6 +146,7 @@ export default Vue.extend({
|
|||
|
||||
methods: {
|
||||
async ok() {
|
||||
if (!this.canOk) return;
|
||||
if (!this.showOkButton) return;
|
||||
|
||||
if (this.user) {
|
||||
|
|
|
@ -92,6 +92,14 @@ export default Vue.extend({
|
|||
|
||||
try {
|
||||
if (this.isFollowing) {
|
||||
const { canceled } = await this.$root.dialog({
|
||||
type: 'warning',
|
||||
text: this.$t('@.unfollow-confirm', { name: this.user.name || this.user.username }),
|
||||
showCancelButton: true
|
||||
});
|
||||
|
||||
if (canceled) return;
|
||||
|
||||
await this.$root.api('following/delete', {
|
||||
userId: this.user.id
|
||||
});
|
||||
|
|
|
@ -15,6 +15,8 @@ export default Vue.extend({
|
|||
|
||||
<style lang="stylus" scoped>
|
||||
.havbbuyv
|
||||
white-space pre-wrap
|
||||
|
||||
>>> .title
|
||||
display block
|
||||
margin-bottom 4px
|
||||
|
|
|
@ -9,7 +9,6 @@ import Vue from 'vue';
|
|||
import i18n from '../../../i18n';
|
||||
import { url } from '../../../config';
|
||||
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
|
||||
import { concat, intersperse } from '../../../../../prelude/array';
|
||||
import { faCopy, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
|
@ -129,6 +128,13 @@ export default Vue.extend({
|
|||
splash: true
|
||||
});
|
||||
this.destroyDom();
|
||||
}).catch(e => {
|
||||
if (e.id === '72dab508-c64d-498f-8740-a8eec1ba385a') {
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('pin-limit-exceeded')
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -1,11 +1,54 @@
|
|||
<template>
|
||||
<div class="2fa">
|
||||
<div class="2fa totp-section">
|
||||
<p style="margin-top:0;">{{ $t('intro') }}<a :href="$t('url')" target="_blank">{{ $t('detail') }}</a></p>
|
||||
<ui-info warn>{{ $t('caution') }}</ui-info>
|
||||
<p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">{{ $t('register') }}</ui-button></p>
|
||||
<template v-if="$store.state.i.twoFactorEnabled">
|
||||
<h2 class="heading">{{ $t('totp-header') }}</h2>
|
||||
<p>{{ $t('already-registered') }}</p>
|
||||
<ui-button @click="unregister">{{ $t('unregister') }}</ui-button>
|
||||
|
||||
<template v-if="supportsCredentials">
|
||||
<hr class="totp-method-sep">
|
||||
|
||||
<h2 class="heading">{{ $t('security-key-header') }}</h2>
|
||||
<p>{{ $t('security-key') }}</p>
|
||||
<div class="key-list">
|
||||
<div class="key" v-for="key in $store.state.i.securityKeysList">
|
||||
<h3>
|
||||
{{ key.name }}
|
||||
</h3>
|
||||
<div class="last-used">
|
||||
{{ $t('last-used') }}
|
||||
<mk-time :time="key.lastUsed"/>
|
||||
</div>
|
||||
<ui-button @click="unregisterKey(key)">
|
||||
{{ $t('unregister') }}
|
||||
</ui-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ui-info warn v-if="registration && registration.error">{{ $t('something-went-wrong') }} {{ registration.error }}</ui-info>
|
||||
<ui-button v-if="!registration || registration.error" @click="addSecurityKey">{{ $t('register') }}</ui-button>
|
||||
|
||||
<ol v-if="registration && !registration.error">
|
||||
<li v-if="registration.stage >= 0">
|
||||
{{ $t('activate-key') }}
|
||||
<fa icon="spinner" pulse fixed-width v-if="registration.saving && registration.stage == 0" />
|
||||
</li>
|
||||
<li v-if="registration.stage >= 1">
|
||||
<ui-form :disabled="registration.stage != 1 || registration.saving">
|
||||
<ui-input v-model="keyName" :max="30">
|
||||
<span>{{ $t('security-key-name') }}</span>
|
||||
</ui-input>
|
||||
<ui-button @click="registerKey" :disabled="this.keyName.length == 0">
|
||||
{{ $t('register-security-key') }}
|
||||
</ui-button>
|
||||
<fa icon="spinner" pulse fixed-width v-if="registration.saving && registration.stage == 1" />
|
||||
</ui-form>
|
||||
</li>
|
||||
</ol>
|
||||
</template>
|
||||
</template>
|
||||
<div v-if="data && !$store.state.i.twoFactorEnabled">
|
||||
<ol>
|
||||
|
@ -24,12 +67,21 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../../i18n';
|
||||
import { hostname } from '../../../../config';
|
||||
import { hexifyAB } from '../../../scripts/2fa';
|
||||
|
||||
function stringifyAB(buffer) {
|
||||
return String.fromCharCode.apply(null, new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('desktop/views/components/settings.2fa.vue'),
|
||||
data() {
|
||||
return {
|
||||
data: null,
|
||||
supportsCredentials: !!navigator.credentials,
|
||||
registration: null,
|
||||
keyName: '',
|
||||
token: null
|
||||
};
|
||||
},
|
||||
|
@ -76,7 +128,116 @@ export default Vue.extend({
|
|||
}).catch(() => {
|
||||
this.$notify(this.$t('failed'));
|
||||
});
|
||||
},
|
||||
|
||||
registerKey() {
|
||||
this.registration.saving = true;
|
||||
this.$root.api('i/2fa/key-done', {
|
||||
password: this.registration.password,
|
||||
name: this.keyName,
|
||||
challengeId: this.registration.challengeId,
|
||||
// we convert each 16 bits to a string to serialise
|
||||
clientDataJSON: stringifyAB(this.registration.credential.response.clientDataJSON),
|
||||
attestationObject: hexifyAB(this.registration.credential.response.attestationObject)
|
||||
}).then(key => {
|
||||
this.registration = null;
|
||||
key.lastUsed = new Date();
|
||||
this.$notify(this.$t('success'));
|
||||
})
|
||||
},
|
||||
|
||||
unregisterKey(key) {
|
||||
this.$root.dialog({
|
||||
title: this.$t('enter-password'),
|
||||
input: {
|
||||
type: 'password'
|
||||
}
|
||||
}).then(({ canceled, result: password }) => {
|
||||
if (canceled) return;
|
||||
return this.$root.api('i/2fa/remove-key', {
|
||||
password,
|
||||
credentialId: key.id
|
||||
}).then(() => {
|
||||
this.$notify(this.$t('key-unregistered'));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
addSecurityKey() {
|
||||
this.$root.dialog({
|
||||
title: this.$t('enter-password'),
|
||||
input: {
|
||||
type: 'password'
|
||||
}
|
||||
}).then(({ canceled, result: password }) => {
|
||||
if (canceled) return;
|
||||
this.$root.api('i/2fa/register-key', {
|
||||
password
|
||||
}).then(registration => {
|
||||
this.registration = {
|
||||
password,
|
||||
challengeId: registration.challengeId,
|
||||
stage: 0,
|
||||
publicKeyOptions: {
|
||||
challenge: Buffer.from(
|
||||
registration.challenge
|
||||
.replace(/\-/g, "+")
|
||||
.replace(/_/g, "/"),
|
||||
'base64'
|
||||
),
|
||||
rp: {
|
||||
id: hostname,
|
||||
name: 'Misskey'
|
||||
},
|
||||
user: {
|
||||
id: Uint8Array.from(this.$store.state.i.id, c => c.charCodeAt(0)),
|
||||
name: this.$store.state.i.username,
|
||||
displayName: this.$store.state.i.name,
|
||||
},
|
||||
pubKeyCredParams: [{alg: -7, type: 'public-key'}],
|
||||
timeout: 60000,
|
||||
attestation: 'direct'
|
||||
},
|
||||
saving: true
|
||||
};
|
||||
return navigator.credentials.create({
|
||||
publicKey: this.registration.publicKeyOptions
|
||||
});
|
||||
}).then(credential => {
|
||||
this.registration.credential = credential;
|
||||
this.registration.saving = false;
|
||||
this.registration.stage = 1;
|
||||
}).catch(err => {
|
||||
console.warn('Error while registering?', err);
|
||||
this.registration.error = err.message;
|
||||
this.registration.stage = -1;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.totp-section
|
||||
.totp-method-sep
|
||||
margin 1.5em 0 1em
|
||||
border none
|
||||
border-top solid var(--lineWidth) var(--faceDivider)
|
||||
|
||||
h2.heading
|
||||
margin 0
|
||||
|
||||
.key
|
||||
padding 1em
|
||||
margin 0.5em 0
|
||||
background #161616
|
||||
border-radius 6px
|
||||
|
||||
h3
|
||||
margin-top 0
|
||||
margin-bottom .3em
|
||||
|
||||
.last-used
|
||||
margin-bottom .5em
|
||||
</style>
|
||||
|
|
|
@ -1,23 +1,40 @@
|
|||
<template>
|
||||
<form class="mk-signin" :class="{ signing }" @submit.prevent="onSubmit">
|
||||
<form class="mk-signin" :class="{ signing, totpLogin }" @submit.prevent="onSubmit">
|
||||
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
|
||||
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange">
|
||||
<span>{{ $t('username') }}</span>
|
||||
<template #prefix>@</template>
|
||||
<template #suffix>@{{ host }}</template>
|
||||
</ui-input>
|
||||
<ui-input v-model="password" type="password" :with-password-toggle="true" required>
|
||||
<span>{{ $t('password') }}</span>
|
||||
<template #prefix><fa icon="lock"/></template>
|
||||
</ui-input>
|
||||
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
|
||||
<span>{{ $t('@.2fa') }}</span>
|
||||
<template #prefix><fa icon="gavel"/></template>
|
||||
</ui-input>
|
||||
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button>
|
||||
<p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`"><fa :icon="['fab', 'twitter']"/> {{ $t('signin-with-twitter') }}</a></p>
|
||||
<p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`"><fa :icon="['fab', 'github']"/> {{ $t('signin-with-github') }}</a></p>
|
||||
<p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`"><fa :icon="['fab', 'discord']"/> {{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
|
||||
<div class="normal-signin" v-if="!totpLogin">
|
||||
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange">
|
||||
<span>{{ $t('username') }}</span>
|
||||
<template #prefix>@</template>
|
||||
<template #suffix>@{{ host }}</template>
|
||||
</ui-input>
|
||||
<ui-input v-model="password" type="password" :with-password-toggle="true" required>
|
||||
<span>{{ $t('password') }}</span>
|
||||
<template #prefix><fa icon="lock"/></template>
|
||||
</ui-input>
|
||||
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button>
|
||||
<p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`"><fa :icon="['fab', 'twitter']"/> {{ $t('signin-with-twitter') }}</a></p>
|
||||
<p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`"><fa :icon="['fab', 'github']"/> {{ $t('signin-with-github') }}</a></p>
|
||||
<p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`"><fa :icon="['fab', 'discord']"/> {{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
|
||||
</div>
|
||||
<div class="2fa-signin" v-if="totpLogin" :class="{ securityKeys: user && user.securityKeys }">
|
||||
<div v-if="user && user.securityKeys" class="twofa-group tap-group">
|
||||
<p>{{ $t('tap-key') }}</p>
|
||||
<ui-button @click="queryKey" v-if="!queryingKey">
|
||||
{{ $t('@.error.retry') }}
|
||||
</ui-button>
|
||||
</div>
|
||||
<div class="or-hr" v-if="user && user.securityKeys">
|
||||
<p class="or-msg">{{ $t('or') }}</p>
|
||||
</div>
|
||||
<div class="twofa-group totp-group">
|
||||
<p style="margin-bottom:0;">{{ $t('enter-2fa-code') }}</p>
|
||||
<ui-input v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
|
||||
<span>{{ $t('@.2fa') }}</span>
|
||||
<template #prefix><fa icon="gavel"/></template>
|
||||
</ui-input>
|
||||
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
@ -26,6 +43,7 @@ import Vue from 'vue';
|
|||
import i18n from '../../../i18n';
|
||||
import { apiUrl, host } from '../../../config';
|
||||
import { toUnicode } from 'punycode';
|
||||
import { hexifyAB } from '../../scripts/2fa';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('common/views/components/signin.vue'),
|
||||
|
@ -47,7 +65,11 @@ export default Vue.extend({
|
|||
token: '',
|
||||
apiUrl,
|
||||
host: toUnicode(host),
|
||||
meta: null
|
||||
meta: null,
|
||||
totpLogin: false,
|
||||
credential: null,
|
||||
challengeData: null,
|
||||
queryingKey: false,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -68,23 +90,87 @@ export default Vue.extend({
|
|||
});
|
||||
},
|
||||
|
||||
onSubmit() {
|
||||
this.signing = true;
|
||||
|
||||
this.$root.api('signin', {
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
token: this.user && this.user.twoFactorEnabled ? this.token : undefined
|
||||
queryKey() {
|
||||
this.queryingKey = true;
|
||||
return navigator.credentials.get({
|
||||
publicKey: {
|
||||
challenge: Buffer.from(
|
||||
this.challengeData.challenge
|
||||
.replace(/\-/g, '+')
|
||||
.replace(/_/g, '/'),
|
||||
'base64'
|
||||
),
|
||||
allowCredentials: this.challengeData.securityKeys.map(key => ({
|
||||
id: Buffer.from(key.id, 'hex'),
|
||||
type: 'public-key',
|
||||
transports: ['usb', 'ble', 'nfc']
|
||||
})),
|
||||
timeout: 60 * 1000
|
||||
}
|
||||
}).catch(err => {
|
||||
this.queryingKey = false;
|
||||
console.warn(err);
|
||||
return Promise.reject(null);
|
||||
}).then(credential => {
|
||||
this.queryingKey = false;
|
||||
this.signing = true;
|
||||
return this.$root.api('signin', {
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
signature: hexifyAB(credential.response.signature),
|
||||
authenticatorData: hexifyAB(credential.response.authenticatorData),
|
||||
clientDataJSON: hexifyAB(credential.response.clientDataJSON),
|
||||
credentialId: credential.id,
|
||||
challengeId: this.challengeData.challengeId
|
||||
});
|
||||
}).then(res => {
|
||||
localStorage.setItem('i', res.i);
|
||||
location.reload();
|
||||
}).catch(() => {
|
||||
}).catch(err => {
|
||||
if(err === null) return;
|
||||
console.error(err);
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('login-failed')
|
||||
});
|
||||
this.signing = false;
|
||||
});
|
||||
},
|
||||
|
||||
onSubmit() {
|
||||
this.signing = true;
|
||||
|
||||
if (!this.totpLogin && this.user && this.user.twoFactorEnabled) {
|
||||
if (window.PublicKeyCredential && this.user.securityKeys) {
|
||||
this.$root.api('i/2fa/getkeys', {
|
||||
username: this.username,
|
||||
password: this.password
|
||||
}).then(res => {
|
||||
this.totpLogin = true;
|
||||
this.signing = false;
|
||||
this.challengeData = res;
|
||||
return this.queryKey();
|
||||
});
|
||||
} else {
|
||||
this.totpLogin = true;
|
||||
this.signing = false;
|
||||
}
|
||||
} else {
|
||||
this.$root.api('signin', {
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
token: this.user && this.user.twoFactorEnabled ? this.token : undefined
|
||||
}).then(res => {
|
||||
localStorage.setItem('i', res.i);
|
||||
location.reload();
|
||||
}).catch(() => {
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('login-failed')
|
||||
});
|
||||
this.signing = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -94,6 +180,48 @@ export default Vue.extend({
|
|||
.mk-signin
|
||||
color #555
|
||||
|
||||
.or-hr,
|
||||
.or-hr .or-msg,
|
||||
.twofa-group,
|
||||
.twofa-group p
|
||||
color var(--text)
|
||||
|
||||
.tap-group > button
|
||||
margin-bottom 1em
|
||||
|
||||
.securityKeys .or-hr
|
||||
&
|
||||
position relative
|
||||
|
||||
.or-msg
|
||||
&:before
|
||||
right 100%
|
||||
margin-right 0.125em
|
||||
|
||||
&:after
|
||||
left 100%
|
||||
margin-left 0.125em
|
||||
|
||||
&:before, &:after
|
||||
content ""
|
||||
position absolute
|
||||
top 50%
|
||||
width 100%
|
||||
height 2px
|
||||
background #555
|
||||
|
||||
&
|
||||
position relative
|
||||
margin auto
|
||||
left 0
|
||||
right 0
|
||||
top 0
|
||||
bottom 0
|
||||
font-size 1.5em
|
||||
height 1.5em
|
||||
width 3em
|
||||
text-align center
|
||||
|
||||
&.signing
|
||||
&, *
|
||||
cursor wait !important
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
<span class="hostname">{{ hostname }}</span>
|
||||
<span class="port" v-if="port != ''">:{{ port }}</span>
|
||||
</template>
|
||||
<template v-if="pathname === '/' && self">
|
||||
<span class="self">{{ hostname }}</span>
|
||||
</template>
|
||||
<span class="pathname" v-if="pathname != ''">{{ self ? pathname.substr(1) : pathname }}</span>
|
||||
<span class="query">{{ query }}</span>
|
||||
<span class="hash">{{ hash }}</span>
|
||||
|
@ -22,6 +25,7 @@ export default Vue.extend({
|
|||
data() {
|
||||
const isSelf = this.url.startsWith(local);
|
||||
const hasRoute = isSelf && (
|
||||
(this.url.substr(local.length) === '/') ||
|
||||
this.url.substr(local.length).startsWith('/@') ||
|
||||
this.url.substr(local.length).startsWith('/notes/') ||
|
||||
this.url.substr(local.length).startsWith('/pages/'));
|
||||
|
@ -54,19 +58,28 @@ export default Vue.extend({
|
|||
<style lang="stylus" scoped>
|
||||
.mk-url
|
||||
word-break break-all
|
||||
|
||||
> [data-icon]
|
||||
padding-left 2px
|
||||
font-size .9em
|
||||
font-weight 400
|
||||
font-style normal
|
||||
|
||||
> .self
|
||||
font-weight bold
|
||||
|
||||
> .schema
|
||||
opacity 0.5
|
||||
|
||||
> .hostname
|
||||
font-weight bold
|
||||
|
||||
> .pathname
|
||||
opacity 0.8
|
||||
|
||||
> .query
|
||||
opacity 0.5
|
||||
|
||||
> .hash
|
||||
font-style italic
|
||||
</style>
|
||||
|
|
|
@ -97,7 +97,9 @@ export default Vue.extend({
|
|||
const image = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif'
|
||||
'image/gif',
|
||||
'image/apng',
|
||||
'image/vnd.mozilla.apng',
|
||||
];
|
||||
|
||||
this.$root.api('users/notes', {
|
||||
|
|
|
@ -91,6 +91,7 @@ export default ($root: any) => {
|
|||
? Promise.resolve(file)
|
||||
: $root.$chooseDriveFile({
|
||||
multiple: false,
|
||||
type: 'image/*',
|
||||
title: locale['desktop']['choose-avatar']
|
||||
});
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ export default ($root: any) => {
|
|||
? Promise.resolve(file)
|
||||
: $root.$chooseDriveFile({
|
||||
multiple: false,
|
||||
type: 'image/*',
|
||||
title: locale['desktop']['choose-banner']
|
||||
});
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ init(async (launch, os) => {
|
|||
if (document.body.clientWidth > 800) {
|
||||
const w = this.$root.new(MkChooseFileFromDriveWindow, {
|
||||
title: o.title,
|
||||
type: o.type,
|
||||
multiple: o.multiple,
|
||||
initFolder: o.currentFolder
|
||||
});
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<x-drive
|
||||
ref="browser"
|
||||
class="browser"
|
||||
:type="type"
|
||||
:multiple="multiple"
|
||||
@selected="onSelected"
|
||||
@change-selection="onChangeSelection"
|
||||
|
@ -33,6 +34,11 @@ export default Vue.extend({
|
|||
XDrive: () => import('./drive.vue').then(m => m.default),
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
multiple: {
|
||||
default: false
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import VueCropper from 'vue-cropperjs';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
import * as url from '../../../../../prelude/url';
|
||||
|
||||
export default Vue.extend({
|
||||
|
|
|
@ -80,6 +80,11 @@ export default Vue.extend({
|
|||
type: Object,
|
||||
required: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
|
@ -540,6 +545,7 @@ export default Vue.extend({
|
|||
// ファイル一覧取得
|
||||
this.$root.api('drive/files', {
|
||||
folderId: this.folder ? this.folder.id : null,
|
||||
type: this.type,
|
||||
limit: filesMax + 1
|
||||
}).then(files => {
|
||||
if (files.length == filesMax + 1) {
|
||||
|
@ -570,6 +576,7 @@ export default Vue.extend({
|
|||
// ファイル一覧取得
|
||||
this.$root.api('drive/files', {
|
||||
folderId: this.folder ? this.folder.id : null,
|
||||
type: this.type,
|
||||
untilId: this.files[this.files.length - 1].id,
|
||||
limit: max + 1
|
||||
}).then(files => {
|
||||
|
|
|
@ -38,7 +38,9 @@ export default Vue.extend({
|
|||
const image = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif'
|
||||
'image/gif',
|
||||
'image/apng',
|
||||
'image/vnd.mozilla.apng',
|
||||
];
|
||||
|
||||
this.$root.api('users/notes', {
|
||||
|
|
|
@ -186,7 +186,9 @@ export default Vue.extend({
|
|||
const image = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif'
|
||||
'image/gif',
|
||||
'image/apng',
|
||||
'image/vnd.mozilla.apng',
|
||||
];
|
||||
|
||||
this.$root.api('notes/local-timeline', {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
</header>
|
||||
<x-drive class="drive" ref="browser"
|
||||
:select-file="true"
|
||||
:type="type"
|
||||
:multiple="multiple"
|
||||
@change-selection="onChangeSelection"
|
||||
@selected="onSelected"
|
||||
|
@ -25,7 +26,7 @@ export default Vue.extend({
|
|||
components: {
|
||||
XDrive: () => import('./drive.vue').then(m => m.default),
|
||||
},
|
||||
props: ['multiple'],
|
||||
props: ['type', 'multiple'],
|
||||
data() {
|
||||
return {
|
||||
files: []
|
||||
|
|
|
@ -30,7 +30,9 @@ export default Vue.extend({
|
|||
const image = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif'
|
||||
'image/gif',
|
||||
'image/apng',
|
||||
'image/vnd.mozilla.apng',
|
||||
];
|
||||
this.$root.api('users/notes', {
|
||||
userId: this.user.id,
|
||||
|
|
|
@ -110,7 +110,9 @@ export default Vue.extend({
|
|||
const image = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif'
|
||||
'image/gif',
|
||||
'image/apng',
|
||||
'image/vnd.mozilla.apng',
|
||||
];
|
||||
|
||||
this.$root.api('notes/local-timeline', {
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import VueRouter from 'vue-router';
|
||||
|
||||
// Style
|
||||
import './style.styl';
|
||||
|
||||
import init from '../init';
|
||||
import Index from './views/index.vue';
|
||||
import NotFound from '../common/views/pages/not-found.vue';
|
||||
|
||||
init(launch => {
|
||||
document.title = 'Misskey';
|
||||
|
||||
// Init router
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: '/test/',
|
||||
routes: [
|
||||
{ path: '/', component: Index },
|
||||
{ path: '*', component: NotFound }
|
||||
]
|
||||
});
|
||||
|
||||
// Launch the app
|
||||
launch(router);
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
@import "../app"
|
||||
@import "../reset"
|
||||
|
||||
html
|
||||
height 100%
|
||||
background var(--bg)
|
|
@ -1,82 +0,0 @@
|
|||
<template>
|
||||
<main>
|
||||
<ui-card>
|
||||
<template #title>MFM Playground</template>
|
||||
<section class="fit-top">
|
||||
<ui-textarea v-model="mfm">
|
||||
<span>MFM</span>
|
||||
</ui-textarea>
|
||||
</section>
|
||||
<section>
|
||||
<header>Preview</header>
|
||||
<mfm :text="mfm" :i="$store.state.i"/>
|
||||
</section>
|
||||
<section>
|
||||
<header style="margin-bottom:0;">AST</header>
|
||||
<ui-textarea v-model="mfmAst" readonly tall style="margin-top:16px;"></ui-textarea>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card>
|
||||
<template #title>Dialog Generator</template>
|
||||
<section class="fit-top">
|
||||
<ui-select v-model="dialogType" placeholder="">
|
||||
<option value="info">Information</option>
|
||||
<option value="success">Success</option>
|
||||
<option value="warning">Warning</option>
|
||||
<option value="error">Error</option>
|
||||
</ui-select>
|
||||
<ui-input v-model="dialogTitle">
|
||||
<span>Title</span>
|
||||
</ui-input>
|
||||
<ui-input v-model="dialogText">
|
||||
<span>Text</span>
|
||||
</ui-input>
|
||||
<ui-switch v-model="dialogShowCancelButton">With cancel button</ui-switch>
|
||||
<ui-button @click="showDialog">Show</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { parse } from '../../../../mfm/parse';
|
||||
import * as JSON5 from 'json5';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
mfm: '',
|
||||
dialogType: 'success',
|
||||
dialogTitle: '',
|
||||
dialogText: 'Hello World!',
|
||||
dialogShowCancelButton: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
mfmAst(): any {
|
||||
return JSON5.stringify(parse(this.mfm), null, 2);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
showDialog() {
|
||||
this.$root.dialog({
|
||||
type: this.dialogType,
|
||||
title: this.dialogTitle,
|
||||
text: this.dialogText,
|
||||
showCancelButton: this.dialogShowCancelButton
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
main
|
||||
max-width 700px
|
||||
margin 0 auto
|
||||
|
||||
</style>
|
18
src/daemons/janitor.ts
Normal file
18
src/daemons/janitor.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
const interval = 30 * 60 * 1000;
|
||||
import { AttestationChallenges } from '../models';
|
||||
import { LessThan } from 'typeorm';
|
||||
|
||||
/**
|
||||
* Clean up database occasionally
|
||||
*/
|
||||
export default function() {
|
||||
async function tick() {
|
||||
await AttestationChallenges.delete({
|
||||
createdAt: LessThan(new Date(new Date().getTime() - 5 * 60 * 1000))
|
||||
});
|
||||
}
|
||||
|
||||
tick();
|
||||
|
||||
setInterval(tick, interval);
|
||||
}
|
|
@ -43,6 +43,8 @@ import { Poll } from '../models/entities/poll';
|
|||
import { UserKeypair } from '../models/entities/user-keypair';
|
||||
import { UserPublickey } from '../models/entities/user-publickey';
|
||||
import { UserProfile } from '../models/entities/user-profile';
|
||||
import { UserSecurityKey } from '../models/entities/user-security-key';
|
||||
import { AttestationChallenge } from '../models/entities/attestation-challenge';
|
||||
import { Page } from '../models/entities/page';
|
||||
import { PageLike } from '../models/entities/page-like';
|
||||
|
||||
|
@ -80,6 +82,53 @@ class MyCustomLogger implements Logger {
|
|||
}
|
||||
}
|
||||
|
||||
export const entities = [
|
||||
Meta,
|
||||
Instance,
|
||||
App,
|
||||
AuthSession,
|
||||
AccessToken,
|
||||
User,
|
||||
UserProfile,
|
||||
UserKeypair,
|
||||
UserPublickey,
|
||||
UserList,
|
||||
UserListJoining,
|
||||
UserGroup,
|
||||
UserGroupJoining,
|
||||
UserGroupInvite,
|
||||
UserNotePining,
|
||||
UserSecurityKey,
|
||||
AttestationChallenge,
|
||||
Following,
|
||||
FollowRequest,
|
||||
Muting,
|
||||
Blocking,
|
||||
Note,
|
||||
NoteFavorite,
|
||||
NoteReaction,
|
||||
NoteWatching,
|
||||
NoteUnread,
|
||||
Page,
|
||||
PageLike,
|
||||
Log,
|
||||
DriveFile,
|
||||
DriveFolder,
|
||||
Poll,
|
||||
PollVote,
|
||||
Notification,
|
||||
Emoji,
|
||||
Hashtag,
|
||||
SwSubscription,
|
||||
AbuseUserReport,
|
||||
RegistrationTicket,
|
||||
MessagingMessage,
|
||||
Signin,
|
||||
ReversiGame,
|
||||
ReversiMatching,
|
||||
...charts as any
|
||||
];
|
||||
|
||||
export function initDb(justBorrow = false, sync = false, log = false) {
|
||||
try {
|
||||
const conn = getConnection();
|
||||
|
@ -101,7 +150,7 @@ export function initDb(justBorrow = false, sync = false, log = false) {
|
|||
options: {
|
||||
host: config.redis.host,
|
||||
port: config.redis.port,
|
||||
options:{
|
||||
options: {
|
||||
password: config.redis.pass,
|
||||
prefix: config.redis.prefix,
|
||||
db: config.redis.db || 0
|
||||
|
@ -110,49 +159,6 @@ export function initDb(justBorrow = false, sync = false, log = false) {
|
|||
} : false,
|
||||
logging: log,
|
||||
logger: log ? new MyCustomLogger() : undefined,
|
||||
entities: [
|
||||
Meta,
|
||||
Instance,
|
||||
App,
|
||||
AuthSession,
|
||||
AccessToken,
|
||||
User,
|
||||
UserProfile,
|
||||
UserKeypair,
|
||||
UserPublickey,
|
||||
UserList,
|
||||
UserListJoining,
|
||||
UserGroup,
|
||||
UserGroupJoining,
|
||||
UserGroupInvite,
|
||||
UserNotePining,
|
||||
Following,
|
||||
FollowRequest,
|
||||
Muting,
|
||||
Blocking,
|
||||
Note,
|
||||
NoteFavorite,
|
||||
NoteReaction,
|
||||
NoteWatching,
|
||||
NoteUnread,
|
||||
Page,
|
||||
PageLike,
|
||||
Log,
|
||||
DriveFile,
|
||||
DriveFolder,
|
||||
Poll,
|
||||
PollVote,
|
||||
Notification,
|
||||
Emoji,
|
||||
Hashtag,
|
||||
SwSubscription,
|
||||
AbuseUserReport,
|
||||
RegistrationTicket,
|
||||
MessagingMessage,
|
||||
Signin,
|
||||
ReversiGame,
|
||||
ReversiMatching,
|
||||
...charts as any
|
||||
]
|
||||
entities: entities
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import { toUnicode } from 'punycode';
|
|||
import { emojiRegex } from '../misc/emoji-regex';
|
||||
|
||||
export function removeOrphanedBrackets(s: string): string {
|
||||
const openBrackets = ['(', '「'];
|
||||
const closeBrackets = [')', '」'];
|
||||
const openBrackets = ['(', '「', '['];
|
||||
const closeBrackets = [')', '」', ']'];
|
||||
const xs = cumulativeSum(s.split('').map(c => {
|
||||
if (openBrackets.includes(c)) return 1;
|
||||
if (closeBrackets.includes(c)) return -1;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import fileType from 'file-type';
|
||||
import fileType = require('file-type');
|
||||
import checkSvg from '../misc/check-svg';
|
||||
|
||||
export async function detectMine(path: string) {
|
||||
|
|
|
@ -5,7 +5,7 @@ import chalk from 'chalk';
|
|||
import Logger from '../services/logger';
|
||||
|
||||
export async function downloadUrl(url: string, path: string) {
|
||||
const logger = new Logger('download-url');
|
||||
const logger = new Logger('download');
|
||||
|
||||
await new Promise((res, rej) => {
|
||||
logger.info(`Downloading ${chalk.cyan(url)} ...`);
|
||||
|
|
|
@ -1,17 +1,3 @@
|
|||
export const types = {
|
||||
boolean: 'boolean' as 'boolean',
|
||||
string: 'string' as 'string',
|
||||
number: 'number' as 'number',
|
||||
array: 'array' as 'array',
|
||||
object: 'object' as 'object',
|
||||
any: 'any' as 'any',
|
||||
};
|
||||
|
||||
export const bool = {
|
||||
true: true as true,
|
||||
false: false as false,
|
||||
};
|
||||
|
||||
export type Schema = {
|
||||
type: 'boolean' | 'number' | 'string' | 'array' | 'object' | 'any';
|
||||
nullable: boolean;
|
||||
|
|
46
src/models/entities/attestation-challenge.ts
Normal file
46
src/models/entities/attestation-challenge.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { PrimaryColumn, Entity, JoinColumn, Column, ManyToOne, Index } from 'typeorm';
|
||||
import { User } from './user';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
export class AttestationChallenge {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@PrimaryColumn(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: User | null;
|
||||
|
||||
@Index()
|
||||
@Column('varchar', {
|
||||
length: 64,
|
||||
comment: 'Hex-encoded sha256 hash of the challenge.'
|
||||
})
|
||||
public challenge: string;
|
||||
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The date challenge was created for expiry purposes.'
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Column('boolean', {
|
||||
comment:
|
||||
'Indicates that the challenge is only for registration purposes if true to prevent the challenge for being used as authentication.',
|
||||
default: false
|
||||
})
|
||||
public registrationChallenge: boolean;
|
||||
|
||||
constructor(data: Partial<AttestationChallenge>) {
|
||||
if (data == null) return;
|
||||
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
(this as any)[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -76,6 +76,11 @@ export class UserProfile {
|
|||
})
|
||||
public twoFactorEnabled: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public securityKeysAvailable: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128, nullable: true,
|
||||
comment: 'The password hash of the User. It will be null if the origin of the user is local.'
|
||||
|
|
48
src/models/entities/user-security-key.ts
Normal file
48
src/models/entities/user-security-key.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { PrimaryColumn, Entity, JoinColumn, Column, ManyToOne, Index } from 'typeorm';
|
||||
import { User } from './user';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
export class UserSecurityKey {
|
||||
@PrimaryColumn('varchar', {
|
||||
comment: 'Variable-length id given to navigator.credentials.get()'
|
||||
})
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: User | null;
|
||||
|
||||
@Index()
|
||||
@Column('varchar', {
|
||||
comment:
|
||||
'Variable-length public key used to verify attestations (hex-encoded).'
|
||||
})
|
||||
public publicKey: string;
|
||||
|
||||
@Column('timestamp with time zone', {
|
||||
comment:
|
||||
'The date of the last time the UserSecurityKey was successfully validated.'
|
||||
})
|
||||
public lastUsed: Date;
|
||||
|
||||
@Column('varchar', {
|
||||
comment: 'User-defined name for this key',
|
||||
length: 30
|
||||
})
|
||||
public name: string;
|
||||
|
||||
constructor(data: Partial<UserSecurityKey>) {
|
||||
if (data == null) return;
|
||||
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
(this as any)[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
export const id = () => ({
|
||||
type: 'varchar' as 'varchar',
|
||||
type: 'varchar' as const,
|
||||
length: 32
|
||||
});
|
||||
|
|
|
@ -37,6 +37,8 @@ import { FollowingRepository } from './repositories/following';
|
|||
import { AbuseUserReportRepository } from './repositories/abuse-user-report';
|
||||
import { AuthSessionRepository } from './repositories/auth-session';
|
||||
import { UserProfile } from './entities/user-profile';
|
||||
import { AttestationChallenge } from './entities/attestation-challenge';
|
||||
import { UserSecurityKey } from './entities/user-security-key';
|
||||
import { HashtagRepository } from './repositories/hashtag';
|
||||
import { PageRepository } from './repositories/page';
|
||||
import { PageLikeRepository } from './repositories/page-like';
|
||||
|
@ -52,6 +54,8 @@ export const PollVotes = getRepository(PollVote);
|
|||
export const Users = getCustomRepository(UserRepository);
|
||||
export const UserProfiles = getRepository(UserProfile);
|
||||
export const UserKeypairs = getRepository(UserKeypair);
|
||||
export const AttestationChallenges = getRepository(AttestationChallenge);
|
||||
export const UserSecurityKeys = getRepository(UserSecurityKey);
|
||||
export const UserPublickeys = getRepository(UserPublickey);
|
||||
export const UserLists = getCustomRepository(UserListRepository);
|
||||
export const UserListJoinings = getRepository(UserListJoining);
|
||||
|
|
|
@ -2,7 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||
import { App } from '../entities/app';
|
||||
import { AccessTokens } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { types, bool, SchemaType } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedApp = SchemaType<typeof packedAppSchema>;
|
||||
|
||||
|
@ -42,37 +42,37 @@ export class AppRepository extends Repository<App> {
|
|||
}
|
||||
|
||||
export const packedAppSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this Note.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
name: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'アプリケーションの名前'
|
||||
},
|
||||
callbackUrl: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
description: 'コールバックするURL'
|
||||
},
|
||||
permission: {
|
||||
type: types.array,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
}
|
||||
},
|
||||
secret: {
|
||||
type: types.string,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
description: 'アプリケーションのシークレットキー'
|
||||
}
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Users } from '..';
|
|||
import { Blocking } from '../entities/blocking';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
import { SchemaType, types, bool } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedBlocking = SchemaType<typeof packedBlockingSchema>;
|
||||
|
||||
|
@ -34,30 +34,30 @@ export class BlockingRepository extends Repository<Blocking> {
|
|||
}
|
||||
|
||||
export const packedBlockingSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this blocking.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the blocking was created.'
|
||||
},
|
||||
blockeeId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
blockee: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: 'The blockee.'
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ import { User } from '../entities/user';
|
|||
import { toPuny } from '../../misc/convert-host';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
import { types, bool, SchemaType } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedDriveFile = SchemaType<typeof packedDriveFileSchema>;
|
||||
|
||||
|
@ -114,63 +114,63 @@ export class DriveFileRepository extends Repository<DriveFile> {
|
|||
}
|
||||
|
||||
export const packedDriveFileSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this Drive file.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the Drive file was created on Misskey.'
|
||||
},
|
||||
name: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The file name with extension.',
|
||||
example: 'lenna.jpg'
|
||||
},
|
||||
type: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The MIME type of this Drive file.',
|
||||
example: 'image/jpeg'
|
||||
},
|
||||
md5: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'md5',
|
||||
description: 'The MD5 hash of this Drive file.',
|
||||
example: '15eca7fba0480996e2245f5185bf39f2'
|
||||
},
|
||||
size: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The size of this Drive file. (bytes)',
|
||||
example: 51469
|
||||
},
|
||||
url: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
format: 'url',
|
||||
description: 'The URL of this Drive file.',
|
||||
},
|
||||
folderId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
format: 'id',
|
||||
description: 'The parent folder ID of this Drive file.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
isSensitive: {
|
||||
type: types.boolean,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'boolean' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'Whether this Drive file is sensitive.',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ import { DriveFolders, DriveFiles } from '..';
|
|||
import { DriveFolder } from '../entities/drive-folder';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
import { SchemaType, types, bool } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedDriveFolder = SchemaType<typeof packedDriveFolderSchema>;
|
||||
|
||||
|
@ -53,47 +53,47 @@ export class DriveFolderRepository extends Repository<DriveFolder> {
|
|||
}
|
||||
|
||||
export const packedDriveFolderSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this Drive folder.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the Drive folder was created.'
|
||||
},
|
||||
name: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The folder name.',
|
||||
},
|
||||
foldersCount: {
|
||||
type: types.number,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
description: 'The count of child folders.',
|
||||
},
|
||||
filesCount: {
|
||||
type: types.number,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
description: 'The count of child files.',
|
||||
},
|
||||
parentId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
format: 'id',
|
||||
description: 'The parent folder ID of this folder.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
parent: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
ref: 'DriveFolder'
|
||||
},
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Users } from '..';
|
|||
import { Following } from '../entities/following';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
import { SchemaType, types, bool } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
type LocalFollowerFollowing = Following & {
|
||||
followerHost: null;
|
||||
|
@ -88,41 +88,41 @@ export class FollowingRepository extends Repository<Following> {
|
|||
}
|
||||
|
||||
export const packedFollowingSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this following.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the following was created.'
|
||||
},
|
||||
followeeId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
followee: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: 'The followee.'
|
||||
},
|
||||
followerId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
follower: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: 'The follower.'
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { EntityRepository, Repository } from 'typeorm';
|
||||
import { Hashtag } from '../entities/hashtag';
|
||||
import { SchemaType, types, bool } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedHashtag = SchemaType<typeof packedHashtagSchema>;
|
||||
|
||||
|
@ -28,43 +28,43 @@ export class HashtagRepository extends Repository<Hashtag> {
|
|||
}
|
||||
|
||||
export const packedHashtagSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
tag: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The hashtag name. No # prefixed.',
|
||||
example: 'misskey',
|
||||
},
|
||||
mentionedUsersCount: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'Number of all users using this hashtag.'
|
||||
},
|
||||
mentionedLocalUsersCount: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'Number of local users using this hashtag.'
|
||||
},
|
||||
mentionedRemoteUsersCount: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'Number of remote users using this hashtag.'
|
||||
},
|
||||
attachedUsersCount: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'Number of all users who attached this hashtag to profile.'
|
||||
},
|
||||
attachedLocalUsersCount: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'Number of local users who attached this hashtag to profile.'
|
||||
},
|
||||
attachedRemoteUsersCount: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'Number of remote users who attached this hashtag to profile.'
|
||||
},
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||
import { MessagingMessage } from '../entities/messaging-message';
|
||||
import { Users, DriveFiles, UserGroups } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { types, bool, SchemaType } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedMessagingMessage = SchemaType<typeof packedMessagingMessageSchema>;
|
||||
|
||||
|
@ -46,76 +46,76 @@ export class MessagingMessageRepository extends Repository<MessagingMessage> {
|
|||
}
|
||||
|
||||
export const packedMessagingMessageSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this MessagingMessage.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the MessagingMessage was created.'
|
||||
},
|
||||
userId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
user: {
|
||||
type: types.object,
|
||||
type: 'object' as const,
|
||||
ref: 'User',
|
||||
optional: bool.true, nullable: bool.false,
|
||||
optional: true as const, nullable: false as const,
|
||||
},
|
||||
text: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
},
|
||||
fileId: {
|
||||
type: types.string,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
format: 'id',
|
||||
},
|
||||
file: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
ref: 'DriveFile',
|
||||
},
|
||||
recipientId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
format: 'id',
|
||||
},
|
||||
recipient: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
ref: 'User'
|
||||
},
|
||||
groupId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
format: 'id',
|
||||
},
|
||||
group: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
ref: 'UserGroup'
|
||||
},
|
||||
isRead: {
|
||||
type: types.boolean,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'boolean' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
},
|
||||
reads: {
|
||||
type: types.array,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id'
|
||||
}
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Users } from '..';
|
|||
import { Muting } from '../entities/muting';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
import { types, bool, SchemaType } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedMuting = SchemaType<typeof packedMutingSchema>;
|
||||
|
||||
|
@ -34,30 +34,30 @@ export class MutingRepository extends Repository<Muting> {
|
|||
}
|
||||
|
||||
export const packedMutingSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this muting.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the muting was created.'
|
||||
},
|
||||
muteeId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
mutee: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: 'The mutee.'
|
||||
},
|
||||
|
|
|
@ -2,7 +2,6 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||
import { NoteFavorite } from '../entities/note-favorite';
|
||||
import { Notes } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { types, bool } from '../../misc/schema';
|
||||
|
||||
@EntityRepository(NoteFavorite)
|
||||
export class NoteFavoriteRepository extends Repository<NoteFavorite> {
|
||||
|
@ -29,30 +28,30 @@ export class NoteFavoriteRepository extends Repository<NoteFavorite> {
|
|||
}
|
||||
|
||||
export const packedNoteFavoriteSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this favorite.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the favorite was created.'
|
||||
},
|
||||
note: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'Note',
|
||||
},
|
||||
noteId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||
import { NoteReaction } from '../entities/note-reaction';
|
||||
import { Users } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { types, bool, SchemaType } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedNoteReaction = SchemaType<typeof packedNoteReactionSchema>;
|
||||
|
||||
|
@ -24,31 +24,31 @@ export class NoteReactionRepository extends Repository<NoteReaction> {
|
|||
}
|
||||
|
||||
export const packedNoteReactionSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this reaction.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the reaction was created.'
|
||||
},
|
||||
user: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: 'User who performed this reaction.'
|
||||
},
|
||||
type: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The reaction type.'
|
||||
},
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ import { unique, concat } from '../../prelude/array';
|
|||
import { nyaize } from '../../misc/nyaize';
|
||||
import { Emojis, Users, Apps, PollVotes, DriveFiles, NoteReactions, Followings, Polls } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { SchemaType, types, bool } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
|
||||
export type PackedNote = SchemaType<typeof packedNoteSchema>;
|
||||
|
@ -144,8 +144,8 @@ export class NoteRepository extends Repository<Note> {
|
|||
|
||||
let text = note.text;
|
||||
|
||||
if (note.name) {
|
||||
text = `【${note.name}】\n${note.text}`;
|
||||
if (note.name && note.uri) {
|
||||
text = `【${note.name}】\n${(note.text || '').trim()}\n${note.uri}`;
|
||||
}
|
||||
|
||||
const reactionEmojis = unique(concat([note.emojis, Object.keys(note.reactions)]));
|
||||
|
@ -218,125 +218,125 @@ export class NoteRepository extends Repository<Note> {
|
|||
}
|
||||
|
||||
export const packedNoteSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this Note.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the Note was created on Misskey.'
|
||||
},
|
||||
text: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
},
|
||||
cw: {
|
||||
type: types.string,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
},
|
||||
userId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
user: {
|
||||
type: types.object,
|
||||
type: 'object' as const,
|
||||
ref: 'User',
|
||||
optional: bool.false, nullable: bool.false,
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
replyId: {
|
||||
type: types.string,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
renoteId: {
|
||||
type: types.string,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
reply: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
ref: 'Note'
|
||||
},
|
||||
renote: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
ref: 'Note'
|
||||
},
|
||||
viaMobile: {
|
||||
type: types.boolean,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'boolean' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
},
|
||||
isHidden: {
|
||||
type: types.boolean,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'boolean' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
},
|
||||
visibility: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
mentions: {
|
||||
type: types.array,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id'
|
||||
}
|
||||
},
|
||||
visibleUserIds: {
|
||||
type: types.array,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id'
|
||||
}
|
||||
},
|
||||
fileIds: {
|
||||
type: types.array,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id'
|
||||
}
|
||||
},
|
||||
files: {
|
||||
type: types.array,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
items: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'DriveFile'
|
||||
}
|
||||
},
|
||||
tags: {
|
||||
type: types.array,
|
||||
optional: bool.true, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: true as const, nullable: false as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
}
|
||||
},
|
||||
poll: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
},
|
||||
geo: {
|
||||
type: types.object,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Users, Notes } from '..';
|
|||
import { Notification } from '../entities/notification';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
import { types, bool, SchemaType } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedNotification = SchemaType<typeof packedNotificationSchema>;
|
||||
|
||||
|
@ -51,37 +51,37 @@ export class NotificationRepository extends Repository<Notification> {
|
|||
}
|
||||
|
||||
export const packedNotificationSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this notification.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the notification was created.'
|
||||
},
|
||||
type: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
enum: ['follow', 'receiveFollowRequest', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote'],
|
||||
description: 'The type of the notification.'
|
||||
},
|
||||
userId: {
|
||||
type: types.string,
|
||||
optional: bool.true, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
format: 'id',
|
||||
},
|
||||
user: {
|
||||
type: types.object,
|
||||
type: 'object' as const,
|
||||
ref: 'User',
|
||||
optional: bool.true, nullable: bool.true,
|
||||
optional: true as const, nullable: true as const,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { EntityRepository, Repository } from 'typeorm';
|
||||
import { Page } from '../entities/page';
|
||||
import { SchemaType, types, bool } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { Users, DriveFiles, PageLikes } from '..';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
import { DriveFile } from '../entities/drive-file';
|
||||
|
@ -89,54 +89,54 @@ export class PageRepository extends Repository<Page> {
|
|||
}
|
||||
|
||||
export const packedPageSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
},
|
||||
updatedAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
},
|
||||
title: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
name: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
summary: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.true,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
},
|
||||
content: {
|
||||
type: types.array,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
variables: {
|
||||
type: types.array,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
userId: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
user: {
|
||||
type: types.object,
|
||||
type: 'object' as const,
|
||||
ref: 'User',
|
||||
optional: bool.false, nullable: bool.false,
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||
import { UserGroup } from '../entities/user-group';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { UserGroupJoinings } from '..';
|
||||
import { bool, types, SchemaType } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedUserGroup = SchemaType<typeof packedUserGroupSchema>;
|
||||
|
||||
|
@ -28,38 +28,38 @@ export class UserGroupRepository extends Repository<UserGroup> {
|
|||
}
|
||||
|
||||
export const packedUserGroupSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this UserGroup.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the UserGroup was created.'
|
||||
},
|
||||
name: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The name of the UserGroup.'
|
||||
},
|
||||
ownerId: {
|
||||
type: types.string,
|
||||
nullable: bool.false, optional: bool.false,
|
||||
type: 'string' as const,
|
||||
nullable: false as const, optional: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
userIds: {
|
||||
type: types.array,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'array' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
nullable: bool.false, optional: bool.false,
|
||||
type: 'string' as const,
|
||||
nullable: false as const, optional: false as const,
|
||||
format: 'id',
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
|||
import { UserList } from '../entities/user-list';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { UserListJoinings } from '..';
|
||||
import { bool, types, SchemaType } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedUserList = SchemaType<typeof packedUserListSchema>;
|
||||
|
||||
|
@ -27,33 +27,33 @@ export class UserListRepository extends Repository<UserList> {
|
|||
}
|
||||
|
||||
export const packedUserListSchema = {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this UserList.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the UserList was created.'
|
||||
},
|
||||
name: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The name of the UserList.'
|
||||
},
|
||||
userIds: {
|
||||
type: types.array,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'array' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
nullable: bool.false, optional: bool.false,
|
||||
type: 'string' as const,
|
||||
nullable: false as const, optional: false as const,
|
||||
format: 'id',
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import $ from 'cafy';
|
||||
import { EntityRepository, Repository, In } from 'typeorm';
|
||||
import { User, ILocalUser, IRemoteUser } from '../entities/user';
|
||||
import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserGroupJoinings } from '..';
|
||||
import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import config from '../../config';
|
||||
import { SchemaType, bool, types } from '../../misc/schema';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
|
||||
export type PackedUser = SchemaType<typeof packedUserSchema>;
|
||||
|
@ -156,6 +156,11 @@ export class UserRepository extends Repository<User> {
|
|||
detail: true
|
||||
}),
|
||||
twoFactorEnabled: profile!.twoFactorEnabled,
|
||||
securityKeys: profile!.twoFactorEnabled
|
||||
? UserSecurityKeys.count({
|
||||
userId: user.id
|
||||
}).then(result => result >= 1)
|
||||
: false,
|
||||
twitter: profile!.twitter ? {
|
||||
id: profile!.twitterUserId,
|
||||
screenName: profile!.twitterScreenName
|
||||
|
@ -195,6 +200,15 @@ export class UserRepository extends Repository<User> {
|
|||
clientData: profile!.clientData,
|
||||
email: profile!.email,
|
||||
emailVerified: profile!.emailVerified,
|
||||
securityKeysList: profile!.twoFactorEnabled
|
||||
? UserSecurityKeys.find({
|
||||
where: {
|
||||
userId: user.id
|
||||
},
|
||||
select: ['id', 'name', 'lastUsed']
|
||||
})
|
||||
: []
|
||||
|
||||
} : {}),
|
||||
|
||||
...(relation ? {
|
||||
|
@ -243,150 +257,150 @@ export class UserRepository extends Repository<User> {
|
|||
}
|
||||
|
||||
export const packedUserSchema = {
|
||||
type: types.object,
|
||||
nullable: bool.false, optional: bool.false,
|
||||
type: 'object' as const,
|
||||
nullable: false as const, optional: false as const,
|
||||
properties: {
|
||||
id: {
|
||||
type: types.string,
|
||||
nullable: bool.false, optional: bool.false,
|
||||
type: 'string' as const,
|
||||
nullable: false as const, optional: false as const,
|
||||
format: 'id',
|
||||
description: 'The unique identifier for this User.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
username: {
|
||||
type: types.string,
|
||||
nullable: bool.false, optional: bool.false,
|
||||
type: 'string' as const,
|
||||
nullable: false as const, optional: false as const,
|
||||
description: 'The screen name, handle, or alias that this user identifies themselves with.',
|
||||
example: 'ai'
|
||||
},
|
||||
name: {
|
||||
type: types.string,
|
||||
nullable: bool.true, optional: bool.false,
|
||||
type: 'string' as const,
|
||||
nullable: true as const, optional: false as const,
|
||||
description: 'The name of the user, as they’ve defined it.',
|
||||
example: '藍'
|
||||
},
|
||||
url: {
|
||||
type: types.string,
|
||||
type: 'string' as const,
|
||||
format: 'url',
|
||||
nullable: bool.true, optional: bool.true,
|
||||
nullable: true as const, optional: true as const,
|
||||
},
|
||||
avatarUrl: {
|
||||
type: types.string,
|
||||
type: 'string' as const,
|
||||
format: 'url',
|
||||
nullable: bool.true, optional: bool.false,
|
||||
nullable: true as const, optional: false as const,
|
||||
},
|
||||
avatarColor: {
|
||||
type: types.any,
|
||||
nullable: bool.true, optional: bool.false,
|
||||
type: 'any' as const,
|
||||
nullable: true as const, optional: false as const,
|
||||
},
|
||||
bannerUrl: {
|
||||
type: types.string,
|
||||
type: 'string' as const,
|
||||
format: 'url',
|
||||
nullable: bool.true, optional: bool.true,
|
||||
nullable: true as const, optional: true as const,
|
||||
},
|
||||
bannerColor: {
|
||||
type: types.any,
|
||||
nullable: bool.true, optional: bool.true,
|
||||
type: 'any' as const,
|
||||
nullable: true as const, optional: true as const,
|
||||
},
|
||||
emojis: {
|
||||
type: types.any,
|
||||
nullable: bool.true, optional: bool.false,
|
||||
type: 'any' as const,
|
||||
nullable: true as const, optional: false as const,
|
||||
},
|
||||
host: {
|
||||
type: types.string,
|
||||
nullable: bool.true, optional: bool.false,
|
||||
type: 'string' as const,
|
||||
nullable: true as const, optional: false as const,
|
||||
example: 'misskey.example.com'
|
||||
},
|
||||
description: {
|
||||
type: types.string,
|
||||
nullable: bool.true, optional: bool.true,
|
||||
type: 'string' as const,
|
||||
nullable: true as const, optional: true as const,
|
||||
description: 'The user-defined UTF-8 string describing their account.',
|
||||
example: 'Hi masters, I am Ai!'
|
||||
},
|
||||
birthday: {
|
||||
type: types.string,
|
||||
nullable: bool.true, optional: bool.true,
|
||||
type: 'string' as const,
|
||||
nullable: true as const, optional: true as const,
|
||||
example: '2018-03-12'
|
||||
},
|
||||
createdAt: {
|
||||
type: types.string,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'string' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the user account was created on Misskey.'
|
||||
},
|
||||
updatedAt: {
|
||||
type: types.string,
|
||||
nullable: bool.true, optional: bool.true,
|
||||
type: 'string' as const,
|
||||
nullable: true as const, optional: true as const,
|
||||
format: 'date-time',
|
||||
},
|
||||
location: {
|
||||
type: types.string,
|
||||
nullable: bool.true, optional: bool.true,
|
||||
type: 'string' as const,
|
||||
nullable: true as const, optional: true as const,
|
||||
},
|
||||
followersCount: {
|
||||
type: types.number,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'number' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
description: 'The number of followers this account currently has.'
|
||||
},
|
||||
followingCount: {
|
||||
type: types.number,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'number' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
description: 'The number of users this account is following.'
|
||||
},
|
||||
notesCount: {
|
||||
type: types.number,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'number' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
description: 'The number of Notes (including renotes) issued by the user.'
|
||||
},
|
||||
isBot: {
|
||||
type: types.boolean,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'boolean' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
description: 'Whether this account is a bot.'
|
||||
},
|
||||
pinnedNoteIds: {
|
||||
type: types.array,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'array' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
items: {
|
||||
type: types.string,
|
||||
nullable: bool.false, optional: bool.false,
|
||||
type: 'string' as const,
|
||||
nullable: false as const, optional: false as const,
|
||||
format: 'id',
|
||||
}
|
||||
},
|
||||
pinnedNotes: {
|
||||
type: types.array,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'array' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
items: {
|
||||
type: types.object,
|
||||
nullable: bool.false, optional: bool.false,
|
||||
type: 'object' as const,
|
||||
nullable: false as const, optional: false as const,
|
||||
ref: 'Note'
|
||||
}
|
||||
},
|
||||
isCat: {
|
||||
type: types.boolean,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'boolean' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
description: 'Whether this account is a cat.'
|
||||
},
|
||||
isAdmin: {
|
||||
type: types.boolean,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'boolean' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
description: 'Whether this account is the admin.'
|
||||
},
|
||||
isModerator: {
|
||||
type: types.boolean,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'boolean' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
description: 'Whether this account is a moderator.'
|
||||
},
|
||||
isLocked: {
|
||||
type: types.boolean,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'boolean' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
},
|
||||
hasUnreadSpecifiedNotes: {
|
||||
type: types.boolean,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'boolean' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
},
|
||||
hasUnreadMentions: {
|
||||
type: types.boolean,
|
||||
nullable: bool.false, optional: bool.true,
|
||||
type: 'boolean' as const,
|
||||
nullable: false as const, optional: true as const,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -194,6 +194,13 @@ export function createDeleteObjectStorageFileJob(key: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export function createCleanRemoteFilesJob() {
|
||||
return objectStorageQueue.add('cleanRemoteFiles', {}, {
|
||||
removeOnComplete: true,
|
||||
removeOnFail: true
|
||||
});
|
||||
}
|
||||
|
||||
export default function() {
|
||||
if (!program.onlyServer) {
|
||||
deliverQueue.process(128, processDeliver);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as Bull from 'bull';
|
||||
|
||||
import { queueLogger } from '../../logger';
|
||||
import { deleteFile } from '../../../services/drive/delete-file';
|
||||
import { deleteFileSync } from '../../../services/drive/delete-file';
|
||||
import { Users, DriveFiles } from '../../../models';
|
||||
import { MoreThan } from 'typeorm';
|
||||
|
||||
|
@ -39,7 +39,7 @@ export async function deleteDriveFiles(job: Bull.Job, done: any): Promise<void>
|
|||
cursor = files[files.length - 1].id;
|
||||
|
||||
for (const file of files) {
|
||||
await deleteFile(file);
|
||||
await deleteFileSync(file);
|
||||
deletedCount++;
|
||||
}
|
||||
|
||||
|
|
50
src/queue/processors/object-storage/clean-remote-files.ts
Normal file
50
src/queue/processors/object-storage/clean-remote-files.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import * as Bull from 'bull';
|
||||
|
||||
import { queueLogger } from '../../logger';
|
||||
import { deleteFileSync } from '../../../services/drive/delete-file';
|
||||
import { DriveFiles } from '../../../models';
|
||||
import { MoreThan, Not, IsNull } from 'typeorm';
|
||||
|
||||
const logger = queueLogger.createSubLogger('clean-remote-files');
|
||||
|
||||
export default async function cleanRemoteFiles(job: Bull.Job, done: any): Promise<void> {
|
||||
logger.info(`Deleting cached remote files...`);
|
||||
|
||||
let deletedCount = 0;
|
||||
let cursor: any = null;
|
||||
|
||||
while (true) {
|
||||
const files = await DriveFiles.find({
|
||||
where: {
|
||||
userHost: Not(IsNull()),
|
||||
isLink: false,
|
||||
...(cursor ? { id: MoreThan(cursor) } : {})
|
||||
},
|
||||
take: 8,
|
||||
order: {
|
||||
id: 1
|
||||
}
|
||||
});
|
||||
|
||||
if (files.length === 0) {
|
||||
job.progress(100);
|
||||
break;
|
||||
}
|
||||
|
||||
cursor = files[files.length - 1].id;
|
||||
|
||||
await Promise.all(files.map(file => deleteFileSync(file, true)));
|
||||
|
||||
deletedCount += 8;
|
||||
|
||||
const total = await DriveFiles.count({
|
||||
userHost: Not(IsNull()),
|
||||
isLink: false,
|
||||
});
|
||||
|
||||
job.progress(deletedCount / total);
|
||||
}
|
||||
|
||||
logger.succ(`All cahced remote files has been deleted.`);
|
||||
done();
|
||||
}
|
|
@ -1,22 +1,10 @@
|
|||
import * as Bull from 'bull';
|
||||
import * as Minio from 'minio';
|
||||
import { fetchMeta } from '../../../misc/fetch-meta';
|
||||
import { deleteObjectStorageFile } from '../../../services/drive/delete-file';
|
||||
|
||||
export default async (job: Bull.Job) => {
|
||||
const meta = await fetchMeta();
|
||||
|
||||
const minio = new Minio.Client({
|
||||
endPoint: meta.objectStorageEndpoint!,
|
||||
region: meta.objectStorageRegion ? meta.objectStorageRegion : undefined,
|
||||
port: meta.objectStoragePort ? meta.objectStoragePort : undefined,
|
||||
useSSL: meta.objectStorageUseSSL,
|
||||
accessKey: meta.objectStorageAccessKey!,
|
||||
secretKey: meta.objectStorageSecretKey!,
|
||||
});
|
||||
|
||||
const key: string = job.data.key;
|
||||
|
||||
await minio.removeObject(meta.objectStorageBucket!, key);
|
||||
await deleteObjectStorageFile(key);
|
||||
|
||||
return 'Success';
|
||||
};
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import * as Bull from 'bull';
|
||||
import deleteFile from './delete-file';
|
||||
import cleanRemoteFiles from './clean-remote-files';
|
||||
|
||||
const jobs = {
|
||||
deleteFile,
|
||||
cleanRemoteFiles,
|
||||
} as any;
|
||||
|
||||
export default function(q: Bull.Queue) {
|
||||
for (const [k, v] of Object.entries(jobs)) {
|
||||
q.process(k, v as any);
|
||||
q.process(k, 16, v as any);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import Resolver from '../../resolver';
|
||||
import { IRemoteUser } from '../../../../models/entities/user';
|
||||
import announceNote from './note';
|
||||
import { IAnnounce, INote } from '../../type';
|
||||
import { IAnnounce, INote, validPost, getApId } from '../../type';
|
||||
import { apLogger } from '../../logger';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IAnnounce): Promise<void> => {
|
||||
const uri = activity.id || activity;
|
||||
const uri = getApId(activity);
|
||||
|
||||
logger.info(`Announce: ${uri}`);
|
||||
|
||||
|
@ -22,15 +22,9 @@ export default async (actor: IRemoteUser, activity: IAnnounce): Promise<void> =>
|
|||
throw e;
|
||||
}
|
||||
|
||||
switch (object.type) {
|
||||
case 'Note':
|
||||
case 'Question':
|
||||
case 'Article':
|
||||
if (validPost.includes(object.type)) {
|
||||
announceNote(resolver, actor, activity, object as INote);
|
||||
break;
|
||||
|
||||
default:
|
||||
} else {
|
||||
logger.warn(`Unknown announce type: ${object.type}`);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Resolver from '../../resolver';
|
||||
import post from '../../../../services/note/create';
|
||||
import { IRemoteUser, User } from '../../../../models/entities/user';
|
||||
import { IAnnounce, INote } from '../../type';
|
||||
import { IAnnounce, INote, getApId, getApIds } from '../../type';
|
||||
import { fetchNote, resolveNote } from '../../models/note';
|
||||
import { resolvePerson } from '../../models/person';
|
||||
import { apLogger } from '../../logger';
|
||||
|
@ -14,17 +14,13 @@ const logger = apLogger;
|
|||
* アナウンスアクティビティを捌きます
|
||||
*/
|
||||
export default async function(resolver: Resolver, actor: IRemoteUser, activity: IAnnounce, note: INote): Promise<void> {
|
||||
const uri = activity.id || activity;
|
||||
const uri = getApId(activity);
|
||||
|
||||
// アナウンサーが凍結されていたらスキップ
|
||||
if (actor.isSuspended) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof uri !== 'string') {
|
||||
throw new Error('invalid announce');
|
||||
}
|
||||
|
||||
// アナウンス先をブロックしてたら中断
|
||||
const meta = await fetchMeta();
|
||||
if (meta.blockedHosts.includes(extractDbHost(uri))) return;
|
||||
|
@ -52,11 +48,14 @@ export default async function(resolver: Resolver, actor: IRemoteUser, activity:
|
|||
logger.info(`Creating the (Re)Note: ${uri}`);
|
||||
|
||||
//#region Visibility
|
||||
const visibility = getVisibility(activity.to || [], activity.cc || [], actor);
|
||||
const to = getApIds(activity.to);
|
||||
const cc = getApIds(activity.cc);
|
||||
|
||||
const visibility = getVisibility(to, cc, actor);
|
||||
|
||||
let visibleUsers: User[] = [];
|
||||
if (visibility == 'specified') {
|
||||
visibleUsers = await Promise.all((note.to || []).map(uri => resolvePerson(uri)));
|
||||
visibleUsers = await Promise.all(to.map(uri => resolvePerson(uri)));
|
||||
}
|
||||
//#endergion
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
import { IRemoteUser } from '../../../../models/entities/user';
|
||||
import { createImage } from '../../models/image';
|
||||
|
||||
export default async function(actor: IRemoteUser, image: any): Promise<void> {
|
||||
await createImage(image.url, actor);
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
import Resolver from '../../resolver';
|
||||
import { IRemoteUser } from '../../../../models/entities/user';
|
||||
import createImage from './image';
|
||||
import createNote from './note';
|
||||
import { ICreate } from '../../type';
|
||||
import { ICreate, getApId, validPost } from '../../type';
|
||||
import { apLogger } from '../../logger';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export default async (actor: IRemoteUser, activity: ICreate): Promise<void> => {
|
||||
const uri = activity.id || activity;
|
||||
const uri = getApId(activity);
|
||||
|
||||
logger.info(`Create: ${uri}`);
|
||||
|
||||
|
@ -23,19 +22,9 @@ export default async (actor: IRemoteUser, activity: ICreate): Promise<void> => {
|
|||
throw e;
|
||||
}
|
||||
|
||||
switch (object.type) {
|
||||
case 'Image':
|
||||
createImage(actor, object);
|
||||
break;
|
||||
|
||||
case 'Note':
|
||||
case 'Question':
|
||||
case 'Article':
|
||||
if (validPost.includes(object.type)) {
|
||||
createNote(resolver, actor, object);
|
||||
break;
|
||||
|
||||
default:
|
||||
} else {
|
||||
logger.warn(`Unknown type: ${object.type}`);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import Resolver from '../../resolver';
|
||||
import deleteNote from './note';
|
||||
import { IRemoteUser } from '../../../../models/entities/user';
|
||||
import { IDelete } from '../../type';
|
||||
import { IDelete, getApId, validPost } from '../../type';
|
||||
import { apLogger } from '../../logger';
|
||||
import { Notes } from '../../../../models';
|
||||
|
||||
/**
|
||||
* 削除アクティビティを捌きます
|
||||
|
@ -17,24 +16,11 @@ export default async (actor: IRemoteUser, activity: IDelete): Promise<void> => {
|
|||
|
||||
const object = await resolver.resolve(activity.object);
|
||||
|
||||
const uri = (object as any).id;
|
||||
const uri = getApId(object);
|
||||
|
||||
switch (object.type) {
|
||||
case 'Note':
|
||||
case 'Question':
|
||||
case 'Article':
|
||||
deleteNote(actor, uri);
|
||||
break;
|
||||
|
||||
case 'Tombstone':
|
||||
const note = await Notes.findOne({ uri });
|
||||
if (note != null) {
|
||||
deleteNote(actor, uri);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
apLogger.warn(`Unknown type: ${object.type}`);
|
||||
break;
|
||||
if (validPost.includes(object.type) || object.type === 'Tombstone') {
|
||||
deleteNote(actor, uri);
|
||||
} else {
|
||||
apLogger.warn(`Unknown type: ${object.type}`);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ import { deliverQuestionUpdate } from '../../../services/note/polls/update';
|
|||
import { extractDbHost, toPuny } from '../../../misc/convert-host';
|
||||
import { Notes, Emojis, Polls } from '../../../models';
|
||||
import { Note } from '../../../models/entities/note';
|
||||
import { IObject, INote } from '../type';
|
||||
import { IObject, INote, getApIds, getOneApId, getApId, validPost } from '../type';
|
||||
import { Emoji } from '../../../models/entities/emoji';
|
||||
import { genId } from '../../../misc/gen-id';
|
||||
import { fetchMeta } from '../../../misc/fetch-meta';
|
||||
|
@ -32,7 +32,7 @@ export function validateNote(object: any, uri: string) {
|
|||
return new Error('invalid Note: object is null');
|
||||
}
|
||||
|
||||
if (!['Note', 'Question', 'Article'].includes(object.type)) {
|
||||
if (!validPost.includes(object.type)) {
|
||||
return new Error(`invalid Note: invalied object type ${object.type}`);
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ export function validateNote(object: any, uri: string) {
|
|||
return new Error(`invalid Note: id has different host. expected: ${expectHost}, actual: ${extractDbHost(object.id)}`);
|
||||
}
|
||||
|
||||
if (object.attributedTo && extractDbHost(object.attributedTo) !== expectHost) {
|
||||
if (object.attributedTo && extractDbHost(getOneApId(object.attributedTo)) !== expectHost) {
|
||||
return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractDbHost(object.attributedTo)}`);
|
||||
}
|
||||
|
||||
|
@ -53,8 +53,7 @@ export function validateNote(object: any, uri: string) {
|
|||
* Misskeyに対象のNoteが登録されていればそれを返します。
|
||||
*/
|
||||
export async function fetchNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
||||
const uri = typeof value == 'string' ? value : value.id;
|
||||
if (uri == null) throw new Error('missing uri');
|
||||
const uri = getApId(value);
|
||||
|
||||
// URIがこのサーバーを指しているならデータベースからフェッチ
|
||||
if (uri.startsWith(config.url + '/')) {
|
||||
|
@ -76,12 +75,12 @@ export async function fetchNote(value: string | IObject, resolver?: Resolver): P
|
|||
/**
|
||||
* Noteを作成します。
|
||||
*/
|
||||
export async function createNote(value: any, resolver?: Resolver, silent = false): Promise<Note | null> {
|
||||
export async function createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise<Note | null> {
|
||||
if (resolver == null) resolver = new Resolver();
|
||||
|
||||
const object: any = await resolver.resolve(value);
|
||||
|
||||
const entryUri = value.id || value;
|
||||
const entryUri = getApId(value);
|
||||
const err = validateNote(object, entryUri);
|
||||
if (err) {
|
||||
logger.error(`${err.message}`, {
|
||||
|
@ -101,7 +100,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
|||
logger.info(`Creating the Note: ${note.id}`);
|
||||
|
||||
// 投稿者をフェッチ
|
||||
const actor = await resolvePerson(note.attributedTo, resolver) as IRemoteUser;
|
||||
const actor = await resolvePerson(getOneApId(note.attributedTo), resolver) as IRemoteUser;
|
||||
|
||||
// 投稿者が凍結されていたらスキップ
|
||||
if (actor.isSuspended) {
|
||||
|
@ -109,24 +108,24 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
|||
}
|
||||
|
||||
//#region Visibility
|
||||
note.to = note.to == null ? [] : typeof note.to == 'string' ? [note.to] : note.to;
|
||||
note.cc = note.cc == null ? [] : typeof note.cc == 'string' ? [note.cc] : note.cc;
|
||||
const to = getApIds(note.to);
|
||||
const cc = getApIds(note.cc);
|
||||
|
||||
let visibility = 'public';
|
||||
let visibleUsers: User[] = [];
|
||||
if (!note.to.includes('https://www.w3.org/ns/activitystreams#Public')) {
|
||||
if (note.cc.includes('https://www.w3.org/ns/activitystreams#Public')) {
|
||||
if (!to.includes('https://www.w3.org/ns/activitystreams#Public')) {
|
||||
if (cc.includes('https://www.w3.org/ns/activitystreams#Public')) {
|
||||
visibility = 'home';
|
||||
} else if (note.to.includes(`${actor.uri}/followers`)) { // TODO: person.followerと照合するべき?
|
||||
} else if (to.includes(`${actor.uri}/followers`)) { // TODO: person.followerと照合するべき?
|
||||
visibility = 'followers';
|
||||
} else {
|
||||
visibility = 'specified';
|
||||
visibleUsers = await Promise.all(note.to.map(uri => resolvePerson(uri, resolver)));
|
||||
visibleUsers = await Promise.all(to.map(uri => resolvePerson(uri, resolver)));
|
||||
}
|
||||
}
|
||||
//#endergion
|
||||
|
||||
const apMentions = await extractMentionedUsers(actor, note.to, note.cc, resolver);
|
||||
const apMentions = await extractMentionedUsers(actor, to, cc, resolver);
|
||||
|
||||
const apHashtags = await extractHashtags(note.tag);
|
||||
|
||||
|
@ -217,11 +216,11 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
|||
const apEmojis = emojis.map(emoji => emoji.name);
|
||||
|
||||
const questionUri = note._misskey_question;
|
||||
const poll = await extractPollFromQuestion(note._misskey_question || note).catch(() => undefined);
|
||||
const poll = await extractPollFromQuestion(note._misskey_question || note, resolver).catch(() => undefined);
|
||||
|
||||
// ユーザーの情報が古かったらついでに更新しておく
|
||||
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
updatePerson(note.attributedTo);
|
||||
if (actor.uri) updatePerson(actor.uri);
|
||||
}
|
||||
|
||||
return await post(actor, {
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import config from '../../../config';
|
||||
import Resolver from '../resolver';
|
||||
import { IQuestion } from '../type';
|
||||
import { IObject, IQuestion, isQuestion, } from '../type';
|
||||
import { apLogger } from '../logger';
|
||||
import { Notes, Polls } from '../../../models';
|
||||
import { IPoll } from '../../../models/entities/poll';
|
||||
|
||||
export async function extractPollFromQuestion(source: string | IQuestion): Promise<IPoll> {
|
||||
const question = typeof source === 'string' ? await new Resolver().resolve(source) as IQuestion : source;
|
||||
export async function extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise<IPoll> {
|
||||
if (resolver == null) resolver = new Resolver();
|
||||
|
||||
const question = await resolver.resolve(source);
|
||||
|
||||
if (!isQuestion(question)) {
|
||||
throw new Error('invalid type');
|
||||
}
|
||||
|
||||
const multiple = !question.oneOf;
|
||||
const expiresAt = question.endTime ? new Date(question.endTime) : null;
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@ export interface IObject {
|
|||
id?: string;
|
||||
summary?: string;
|
||||
published?: string;
|
||||
cc?: string[];
|
||||
to?: string[];
|
||||
attributedTo: string;
|
||||
cc?: IObject | string | (IObject | string)[];
|
||||
to?: IObject | string | (IObject | string)[];
|
||||
attributedTo: IObject | string | (IObject | string)[];
|
||||
attachment?: any[];
|
||||
inReplyTo?: any;
|
||||
replies?: ICollection;
|
||||
|
@ -23,6 +23,32 @@ export interface IObject {
|
|||
sensitive?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of ActivityStreams Objects id
|
||||
*/
|
||||
export function getApIds(value: IObject | string | (IObject | string)[] | undefined): string[] {
|
||||
if (value == null) return [];
|
||||
const array = Array.isArray(value) ? value : [value];
|
||||
return array.map(x => getApId(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get first ActivityStreams Object id
|
||||
*/
|
||||
export function getOneApId(value: IObject | string | (IObject | string)[]): string {
|
||||
const firstOne = Array.isArray(value) ? value[0] : value;
|
||||
return getApId(firstOne);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ActivityStreams Object id
|
||||
*/
|
||||
export function getApId(value: string | IObject): string {
|
||||
if (typeof value === 'string') return value;
|
||||
if (typeof value.id === 'string') return value.id;
|
||||
throw new Error(`cannot detemine id`);
|
||||
}
|
||||
|
||||
export interface IActivity extends IObject {
|
||||
//type: 'Activity';
|
||||
actor: IObject | string;
|
||||
|
@ -42,8 +68,10 @@ export interface IOrderedCollection extends IObject {
|
|||
orderedItems: IObject | string | IObject[] | string[];
|
||||
}
|
||||
|
||||
export const validPost = ['Note', 'Question', 'Article', 'Audio', 'Document', 'Image', 'Page', 'Video'];
|
||||
|
||||
export interface INote extends IObject {
|
||||
type: 'Note' | 'Question';
|
||||
type: 'Note' | 'Question' | 'Article' | 'Audio' | 'Document' | 'Image' | 'Page' | 'Video';
|
||||
_misskey_content?: string;
|
||||
_misskey_quote?: string;
|
||||
_misskey_question?: string;
|
||||
|
@ -59,6 +87,9 @@ export interface IQuestion extends IObject {
|
|||
endTime?: Date;
|
||||
}
|
||||
|
||||
export const isQuestion = (object: IObject): object is IQuestion =>
|
||||
object.type === 'Note' || object.type === 'Question';
|
||||
|
||||
interface IQuestionChoice {
|
||||
name?: string;
|
||||
replies?: ICollection;
|
||||
|
|
422
src/server/api/2fa.ts
Normal file
422
src/server/api/2fa.ts
Normal file
|
@ -0,0 +1,422 @@
|
|||
import * as crypto from 'crypto';
|
||||
import config from '../../config';
|
||||
import * as jsrsasign from 'jsrsasign';
|
||||
|
||||
const ECC_PRELUDE = Buffer.from([0x04]);
|
||||
const NULL_BYTE = Buffer.from([0]);
|
||||
const PEM_PRELUDE = Buffer.from(
|
||||
'3059301306072a8648ce3d020106082a8648ce3d030107034200',
|
||||
'hex'
|
||||
);
|
||||
|
||||
// Android Safetynet attestations are signed with this cert:
|
||||
const GSR2 = `-----BEGIN CERTIFICATE-----
|
||||
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
|
||||
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
|
||||
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
|
||||
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
|
||||
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
|
||||
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
|
||||
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
|
||||
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
|
||||
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
|
||||
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
|
||||
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
|
||||
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
|
||||
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
|
||||
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
|
||||
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
|
||||
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
|
||||
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
|
||||
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
|
||||
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
|
||||
-----END CERTIFICATE-----\n`;
|
||||
|
||||
function base64URLDecode(source: string) {
|
||||
return Buffer.from(source.replace(/\-/g, '+').replace(/_/g, '/'), 'base64');
|
||||
}
|
||||
|
||||
function getCertSubject(certificate: string) {
|
||||
const subjectCert = new jsrsasign.X509();
|
||||
subjectCert.readCertPEM(certificate);
|
||||
|
||||
const subjectString = subjectCert.getSubjectString();
|
||||
const subjectFields = subjectString.slice(1).split('/');
|
||||
|
||||
const fields = {} as Record<string, string>;
|
||||
for (const field of subjectFields) {
|
||||
const eqIndex = field.indexOf('=');
|
||||
fields[field.substring(0, eqIndex)] = field.substring(eqIndex + 1);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
function verifyCertificateChain(certificates: string[]) {
|
||||
let valid = true;
|
||||
|
||||
for (let i = 0; i < certificates.length; i++) {
|
||||
const Cert = certificates[i];
|
||||
const certificate = new jsrsasign.X509();
|
||||
certificate.readCertPEM(Cert);
|
||||
|
||||
const CACert = i + 1 >= certificates.length ? Cert : certificates[i + 1];
|
||||
|
||||
const certStruct = jsrsasign.ASN1HEX.getTLVbyList(certificate.hex!, 0, [0]);
|
||||
const algorithm = certificate.getSignatureAlgorithmField();
|
||||
const signatureHex = certificate.getSignatureValueHex();
|
||||
|
||||
// Verify against CA
|
||||
const Signature = new jsrsasign.KJUR.crypto.Signature({alg: algorithm});
|
||||
Signature.init(CACert);
|
||||
Signature.updateHex(certStruct);
|
||||
valid = valid && !!Signature.verify(signatureHex); // true if CA signed the certificate
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
function PEMString(pemBuffer: Buffer, type = 'CERTIFICATE') {
|
||||
if (pemBuffer.length == 65 && pemBuffer[0] == 0x04) {
|
||||
pemBuffer = Buffer.concat([PEM_PRELUDE, pemBuffer], 91);
|
||||
type = 'PUBLIC KEY';
|
||||
}
|
||||
const cert = pemBuffer.toString('base64');
|
||||
|
||||
const keyParts = [];
|
||||
const max = Math.ceil(cert.length / 64);
|
||||
let start = 0;
|
||||
for (let i = 0; i < max; i++) {
|
||||
keyParts.push(cert.substring(start, start + 64));
|
||||
start += 64;
|
||||
}
|
||||
|
||||
return (
|
||||
`-----BEGIN ${type}-----\n` +
|
||||
keyParts.join('\n') +
|
||||
`\n-----END ${type}-----\n`
|
||||
);
|
||||
}
|
||||
|
||||
export function hash(data: Buffer) {
|
||||
return crypto
|
||||
.createHash('sha256')
|
||||
.update(data)
|
||||
.digest();
|
||||
}
|
||||
|
||||
export function verifyLogin({
|
||||
publicKey,
|
||||
authenticatorData,
|
||||
clientDataJSON,
|
||||
clientData,
|
||||
signature,
|
||||
challenge
|
||||
}: {
|
||||
publicKey: Buffer,
|
||||
authenticatorData: Buffer,
|
||||
clientDataJSON: Buffer,
|
||||
clientData: any,
|
||||
signature: Buffer,
|
||||
challenge: string
|
||||
}) {
|
||||
if (clientData.type != 'webauthn.get') {
|
||||
throw new Error('type is not webauthn.get');
|
||||
}
|
||||
|
||||
if (hash(clientData.challenge).toString('hex') != challenge) {
|
||||
throw new Error('challenge mismatch');
|
||||
}
|
||||
if (clientData.origin != config.scheme + '://' + config.host) {
|
||||
throw new Error('origin mismatch');
|
||||
}
|
||||
|
||||
const verificationData = Buffer.concat(
|
||||
[authenticatorData, hash(clientDataJSON)],
|
||||
32 + authenticatorData.length
|
||||
);
|
||||
|
||||
return crypto
|
||||
.createVerify('SHA256')
|
||||
.update(verificationData)
|
||||
.verify(PEMString(publicKey), signature);
|
||||
}
|
||||
|
||||
export const procedures = {
|
||||
none: {
|
||||
verify({publicKey}: {publicKey: Map<number, Buffer>}) {
|
||||
const negTwo = publicKey.get(-2);
|
||||
|
||||
if (!negTwo || negTwo.length != 32) {
|
||||
throw new Error('invalid or no -2 key given');
|
||||
}
|
||||
const negThree = publicKey.get(-3);
|
||||
if (!negThree || negThree.length != 32) {
|
||||
throw new Error('invalid or no -3 key given');
|
||||
}
|
||||
|
||||
const publicKeyU2F = Buffer.concat(
|
||||
[ECC_PRELUDE, negTwo, negThree],
|
||||
1 + 32 + 32
|
||||
);
|
||||
|
||||
return {
|
||||
publicKey: publicKeyU2F,
|
||||
valid: true
|
||||
};
|
||||
}
|
||||
},
|
||||
'android-key': {
|
||||
verify({
|
||||
attStmt,
|
||||
authenticatorData,
|
||||
clientDataHash,
|
||||
publicKey,
|
||||
rpIdHash,
|
||||
credentialId
|
||||
}: {
|
||||
attStmt: any,
|
||||
authenticatorData: Buffer,
|
||||
clientDataHash: Buffer,
|
||||
publicKey: Map<number, any>;
|
||||
rpIdHash: Buffer,
|
||||
credentialId: Buffer,
|
||||
}) {
|
||||
if (attStmt.alg != -7) {
|
||||
throw new Error('alg mismatch');
|
||||
}
|
||||
|
||||
const verificationData = Buffer.concat([
|
||||
authenticatorData,
|
||||
clientDataHash
|
||||
]);
|
||||
|
||||
const attCert: Buffer = attStmt.x5c[0];
|
||||
|
||||
const negTwo = publicKey.get(-2);
|
||||
|
||||
if (!negTwo || negTwo.length != 32) {
|
||||
throw new Error('invalid or no -2 key given');
|
||||
}
|
||||
const negThree = publicKey.get(-3);
|
||||
if (!negThree || negThree.length != 32) {
|
||||
throw new Error('invalid or no -3 key given');
|
||||
}
|
||||
|
||||
const publicKeyData = Buffer.concat(
|
||||
[ECC_PRELUDE, negTwo, negThree],
|
||||
1 + 32 + 32
|
||||
);
|
||||
|
||||
if (!attCert.equals(publicKeyData)) {
|
||||
throw new Error('public key mismatch');
|
||||
}
|
||||
|
||||
const isValid = crypto
|
||||
.createVerify('SHA256')
|
||||
.update(verificationData)
|
||||
.verify(PEMString(attCert), attStmt.sig);
|
||||
|
||||
// TODO: Check 'attestationChallenge' field in extension of cert matches hash(clientDataJSON)
|
||||
|
||||
return {
|
||||
valid: isValid,
|
||||
publicKey: publicKeyData
|
||||
};
|
||||
}
|
||||
},
|
||||
// what a stupid attestation
|
||||
'android-safetynet': {
|
||||
verify({
|
||||
attStmt,
|
||||
authenticatorData,
|
||||
clientDataHash,
|
||||
publicKey,
|
||||
rpIdHash,
|
||||
credentialId
|
||||
}: {
|
||||
attStmt: any,
|
||||
authenticatorData: Buffer,
|
||||
clientDataHash: Buffer,
|
||||
publicKey: Map<number, any>;
|
||||
rpIdHash: Buffer,
|
||||
credentialId: Buffer,
|
||||
}) {
|
||||
const verificationData = hash(
|
||||
Buffer.concat([authenticatorData, clientDataHash])
|
||||
);
|
||||
|
||||
const jwsParts = attStmt.response.toString('utf-8').split('.');
|
||||
|
||||
const header = JSON.parse(base64URLDecode(jwsParts[0]).toString('utf-8'));
|
||||
const response = JSON.parse(
|
||||
base64URLDecode(jwsParts[1]).toString('utf-8')
|
||||
);
|
||||
const signature = jwsParts[2];
|
||||
|
||||
if (!verificationData.equals(Buffer.from(response.nonce, 'base64'))) {
|
||||
throw new Error('invalid nonce');
|
||||
}
|
||||
|
||||
const certificateChain = header.x5c
|
||||
.map((key: any) => PEMString(key))
|
||||
.concat([GSR2]);
|
||||
|
||||
if (getCertSubject(certificateChain[0]).CN != 'attest.android.com') {
|
||||
throw new Error('invalid common name');
|
||||
}
|
||||
|
||||
if (!verifyCertificateChain(certificateChain)) {
|
||||
throw new Error('Invalid certificate chain!');
|
||||
}
|
||||
|
||||
const signatureBase = Buffer.from(
|
||||
jwsParts[0] + '.' + jwsParts[1],
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
const valid = crypto
|
||||
.createVerify('sha256')
|
||||
.update(signatureBase)
|
||||
.verify(certificateChain[0], base64URLDecode(signature));
|
||||
|
||||
const negTwo = publicKey.get(-2);
|
||||
|
||||
if (!negTwo || negTwo.length != 32) {
|
||||
throw new Error('invalid or no -2 key given');
|
||||
}
|
||||
const negThree = publicKey.get(-3);
|
||||
if (!negThree || negThree.length != 32) {
|
||||
throw new Error('invalid or no -3 key given');
|
||||
}
|
||||
|
||||
const publicKeyData = Buffer.concat(
|
||||
[ECC_PRELUDE, negTwo, negThree],
|
||||
1 + 32 + 32
|
||||
);
|
||||
return {
|
||||
valid,
|
||||
publicKey: publicKeyData
|
||||
};
|
||||
}
|
||||
},
|
||||
packed: {
|
||||
verify({
|
||||
attStmt,
|
||||
authenticatorData,
|
||||
clientDataHash,
|
||||
publicKey,
|
||||
rpIdHash,
|
||||
credentialId
|
||||
}: {
|
||||
attStmt: any,
|
||||
authenticatorData: Buffer,
|
||||
clientDataHash: Buffer,
|
||||
publicKey: Map<number, any>;
|
||||
rpIdHash: Buffer,
|
||||
credentialId: Buffer,
|
||||
}) {
|
||||
const verificationData = Buffer.concat([
|
||||
authenticatorData,
|
||||
clientDataHash
|
||||
]);
|
||||
|
||||
if (attStmt.x5c) {
|
||||
const attCert = attStmt.x5c[0];
|
||||
|
||||
const validSignature = crypto
|
||||
.createVerify('SHA256')
|
||||
.update(verificationData)
|
||||
.verify(PEMString(attCert), attStmt.sig);
|
||||
|
||||
const negTwo = publicKey.get(-2);
|
||||
|
||||
if (!negTwo || negTwo.length != 32) {
|
||||
throw new Error('invalid or no -2 key given');
|
||||
}
|
||||
const negThree = publicKey.get(-3);
|
||||
if (!negThree || negThree.length != 32) {
|
||||
throw new Error('invalid or no -3 key given');
|
||||
}
|
||||
|
||||
const publicKeyData = Buffer.concat(
|
||||
[ECC_PRELUDE, negTwo, negThree],
|
||||
1 + 32 + 32
|
||||
);
|
||||
|
||||
return {
|
||||
valid: validSignature,
|
||||
publicKey: publicKeyData
|
||||
};
|
||||
} else if (attStmt.ecdaaKeyId) {
|
||||
// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-ecdaa-algorithm-v2.0-id-20180227.html#ecdaa-verify-operation
|
||||
throw new Error('ECDAA-Verify is not supported');
|
||||
} else {
|
||||
if (attStmt.alg != -7) throw new Error('alg mismatch');
|
||||
|
||||
throw new Error('self attestation is not supported');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'fido-u2f': {
|
||||
verify({
|
||||
attStmt,
|
||||
authenticatorData,
|
||||
clientDataHash,
|
||||
publicKey,
|
||||
rpIdHash,
|
||||
credentialId
|
||||
}: {
|
||||
attStmt: any,
|
||||
authenticatorData: Buffer,
|
||||
clientDataHash: Buffer,
|
||||
publicKey: Map<number, any>,
|
||||
rpIdHash: Buffer,
|
||||
credentialId: Buffer
|
||||
}) {
|
||||
const x5c: Buffer[] = attStmt.x5c;
|
||||
if (x5c.length != 1) {
|
||||
throw new Error('x5c length does not match expectation');
|
||||
}
|
||||
|
||||
const attCert = x5c[0];
|
||||
|
||||
// TODO: make sure attCert is an Elliptic Curve (EC) public key over the P-256 curve
|
||||
|
||||
const negTwo: Buffer = publicKey.get(-2);
|
||||
|
||||
if (!negTwo || negTwo.length != 32) {
|
||||
throw new Error('invalid or no -2 key given');
|
||||
}
|
||||
const negThree: Buffer = publicKey.get(-3);
|
||||
if (!negThree || negThree.length != 32) {
|
||||
throw new Error('invalid or no -3 key given');
|
||||
}
|
||||
|
||||
const publicKeyU2F = Buffer.concat(
|
||||
[ECC_PRELUDE, negTwo, negThree],
|
||||
1 + 32 + 32
|
||||
);
|
||||
|
||||
const verificationData = Buffer.concat([
|
||||
NULL_BYTE,
|
||||
rpIdHash,
|
||||
clientDataHash,
|
||||
credentialId,
|
||||
publicKeyU2F
|
||||
]);
|
||||
|
||||
const validSignature = crypto
|
||||
.createVerify('SHA256')
|
||||
.update(verificationData)
|
||||
.verify(PEMString(attCert), attStmt.sig);
|
||||
|
||||
return {
|
||||
valid: validSignature,
|
||||
publicKey: publicKeyU2F
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,7 +1,5 @@
|
|||
import { Not, IsNull } from 'typeorm';
|
||||
import define from '../../../define';
|
||||
import { deleteFile } from '../../../../../services/drive/delete-file';
|
||||
import { DriveFiles } from '../../../../../models';
|
||||
import { createCleanRemoteFilesJob } from '../../../../../queue';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
@ -11,12 +9,5 @@ export const meta = {
|
|||
};
|
||||
|
||||
export default define(meta, async (ps, me) => {
|
||||
const files = await DriveFiles.find({
|
||||
userHost: Not(IsNull()),
|
||||
isLink: false,
|
||||
});
|
||||
|
||||
for (const file of files) {
|
||||
deleteFile(file, true);
|
||||
}
|
||||
createCleanRemoteFilesJob();
|
||||
});
|
||||
|
|
26
src/server/api/endpoints/admin/send-email.ts
Normal file
26
src/server/api/endpoints/admin/send-email.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import $ from 'cafy';
|
||||
import define from '../../define';
|
||||
import { sendEmail } from '../../../../services/send-email';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
params: {
|
||||
to: {
|
||||
validator: $.str,
|
||||
},
|
||||
subject: {
|
||||
validator: $.str,
|
||||
},
|
||||
text: {
|
||||
validator: $.str,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps) => {
|
||||
await sendEmail(ps.to, ps.subject, ps.text);
|
||||
});
|
33
src/server/api/endpoints/admin/vacuum.ts
Normal file
33
src/server/api/endpoints/admin/vacuum.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import $ from 'cafy';
|
||||
import define from '../../define';
|
||||
import { getConnection } from 'typeorm';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
params: {
|
||||
full: {
|
||||
validator: $.bool,
|
||||
},
|
||||
analyze: {
|
||||
validator: $.bool,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps) => {
|
||||
const params: string[] = [];
|
||||
|
||||
if (ps.full) {
|
||||
params.push('FULL');
|
||||
}
|
||||
|
||||
if (ps.analyze) {
|
||||
params.push('ANALYZE');
|
||||
}
|
||||
|
||||
getConnection().query('VACUUM ' + params.join(' '));
|
||||
});
|
|
@ -10,7 +10,7 @@ import { Users, Notes } from '../../../../models';
|
|||
import { Note } from '../../../../models/entities/note';
|
||||
import { User } from '../../../../models/entities/user';
|
||||
import { fetchMeta } from '../../../../misc/fetch-meta';
|
||||
import { validActor } from '../../../../remote/activitypub/type';
|
||||
import { validActor, validPost } from '../../../../remote/activitypub/type';
|
||||
|
||||
export const meta = {
|
||||
tags: ['federation'],
|
||||
|
@ -145,7 +145,7 @@ async function fetchAny(uri: string) {
|
|||
};
|
||||
}
|
||||
|
||||
if (['Note', 'Question', 'Article'].includes(object.type)) {
|
||||
if (validPost.includes(object.type)) {
|
||||
const note = await createNote(object.id, undefined, true);
|
||||
return {
|
||||
type: 'Note',
|
||||
|
|
|
@ -4,7 +4,6 @@ import define from '../../define';
|
|||
import { Apps } from '../../../../models';
|
||||
import { genId } from '../../../../misc/gen-id';
|
||||
import { unique } from '../../../../prelude/array';
|
||||
import { types, bool } from '../../../../misc/schema';
|
||||
|
||||
export const meta = {
|
||||
tags: ['app'],
|
||||
|
@ -53,8 +52,8 @@ export const meta = {
|
|||
},
|
||||
|
||||
res: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'App',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ID } from '../../../../misc/cafy-id';
|
|||
import define from '../../define';
|
||||
import { ApiError } from '../../error';
|
||||
import { Apps } from '../../../../models';
|
||||
import { types, bool } from '../../../../misc/schema';
|
||||
|
||||
export const meta = {
|
||||
tags: ['app'],
|
||||
|
@ -15,8 +14,8 @@ export const meta = {
|
|||
},
|
||||
|
||||
res: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'App',
|
||||
},
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import define from '../../../define';
|
|||
import { ApiError } from '../../../error';
|
||||
import { Apps, AuthSessions } from '../../../../../models';
|
||||
import { genId } from '../../../../../misc/gen-id';
|
||||
import { types, bool } from '../../../../../misc/schema';
|
||||
|
||||
export const meta = {
|
||||
tags: ['auth'],
|
||||
|
@ -28,17 +27,17 @@ export const meta = {
|
|||
},
|
||||
|
||||
res: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
token: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'セッションのトークン'
|
||||
},
|
||||
url: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'url',
|
||||
description: 'セッションのURL'
|
||||
},
|
||||
|
|
|
@ -3,7 +3,6 @@ import define from '../../../define';
|
|||
import { ApiError } from '../../../error';
|
||||
import { Apps, AuthSessions, AccessTokens, Users } from '../../../../../models';
|
||||
import { ensure } from '../../../../../prelude/ensure';
|
||||
import { types, bool } from '../../../../../misc/schema';
|
||||
|
||||
export const meta = {
|
||||
tags: ['auth'],
|
||||
|
@ -29,18 +28,18 @@ export const meta = {
|
|||
},
|
||||
|
||||
res: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
accessToken: {
|
||||
type: types.string,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'ユーザーのアクセストークン',
|
||||
},
|
||||
|
||||
user: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'User',
|
||||
description: '認証したユーザー'
|
||||
},
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ID } from '../../../../misc/cafy-id';
|
|||
import define from '../../define';
|
||||
import { Blockings } from '../../../../models';
|
||||
import { makePaginationQuery } from '../../common/make-pagination-query';
|
||||
import { types, bool } from '../../../../misc/schema';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
|
@ -33,11 +32,11 @@ export const meta = {
|
|||
},
|
||||
|
||||
res: {
|
||||
type: types.array,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'array' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
items: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
ref: 'Blocking',
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import define from '../define';
|
||||
import { fetchMeta } from '../../../misc/fetch-meta';
|
||||
import { DriveFiles } from '../../../models';
|
||||
import { types, bool } from '../../../misc/schema';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
|
@ -16,16 +15,16 @@ export const meta = {
|
|||
kind: 'read:drive',
|
||||
|
||||
res: {
|
||||
type: types.object,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'object' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
properties: {
|
||||
capacity: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
usage: {
|
||||
type: types.number,
|
||||
optional: bool.false, nullable: bool.false,
|
||||
type: 'number' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue