Merge branch 'develop' into enhance-thread-mute
This commit is contained in:
commit
850251afb2
|
@ -220,5 +220,10 @@ allowedPrivateNetworks: [
|
||||||
'127.0.0.1/32'
|
'127.0.0.1/32'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Disable automatic redirect for ActivityPub object lookup. (default: false)
|
||||||
|
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
|
||||||
|
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
|
||||||
|
#disallowExternalApRedirect: true
|
||||||
|
|
||||||
# Upload or download file size limits (bytes)
|
# Upload or download file size limits (bytes)
|
||||||
#maxFileSize: 262144000
|
#maxFileSize: 262144000
|
||||||
|
|
|
@ -235,6 +235,11 @@ signToActivityPubGet: true
|
||||||
# '127.0.0.1/32'
|
# '127.0.0.1/32'
|
||||||
#]
|
#]
|
||||||
|
|
||||||
|
# Disable automatic redirect for ActivityPub object lookup. (default: false)
|
||||||
|
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
|
||||||
|
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
|
||||||
|
#disallowExternalApRedirect: true
|
||||||
|
|
||||||
# Upload or download file size limits (bytes)
|
# Upload or download file size limits (bytes)
|
||||||
#maxFileSize: 262144000
|
#maxFileSize: 262144000
|
||||||
|
|
||||||
|
|
|
@ -334,6 +334,11 @@ signToActivityPubGet: true
|
||||||
# '127.0.0.1/32'
|
# '127.0.0.1/32'
|
||||||
#]
|
#]
|
||||||
|
|
||||||
|
# Disable automatic redirect for ActivityPub object lookup. (default: false)
|
||||||
|
# This is a strong defense against potential impersonation attacks if the viewer instance has inadequate validation.
|
||||||
|
# However it will make it impossible for other instances to lookup third-party user and notes through your URL.
|
||||||
|
#disallowExternalApRedirect: true
|
||||||
|
|
||||||
# Upload or download file size limits (bytes)
|
# Upload or download file size limits (bytes)
|
||||||
#maxFileSize: 262144000
|
#maxFileSize: 262144000
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version": "22.11.0"
|
"version": "22.11.0"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers-contrib/features/corepack:1": {}
|
"ghcr.io/devcontainers-extra/features/corepack:1": {
|
||||||
|
"version": "0.31.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"forwardPorts": [3000],
|
"forwardPorts": [3000],
|
||||||
"postCreateCommand": "/bin/bash .devcontainer/init.sh",
|
"postCreateCommand": "/bin/bash .devcontainer/init.sh",
|
||||||
|
|
|
@ -9,7 +9,7 @@ updates:
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
open-pull-requests-limit: 100
|
open-pull-requests-limit: 0
|
||||||
|
|
||||||
# Add only the root, not each workspace item
|
# Add only the root, not each workspace item
|
||||||
# https://github.com/dependabot/dependabot-core/issues/4993#issuecomment-1289133027
|
# https://github.com/dependabot/dependabot-core/issues/4993#issuecomment-1289133027
|
||||||
|
@ -17,7 +17,7 @@ updates:
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
open-pull-requests-limit: 10
|
open-pull-requests-limit: 0
|
||||||
# List dependencies required to be updated together, sharing the same version numbers.
|
# List dependencies required to be updated together, sharing the same version numbers.
|
||||||
# Those who simply have the common owner (e.g. @fastify) don't need to be listed.
|
# Those who simply have the common owner (e.g. @fastify) don't need to be listed.
|
||||||
groups:
|
groups:
|
||||||
|
|
|
@ -20,12 +20,12 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -12,9 +12,9 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout head
|
- name: Checkout head
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ jobs:
|
||||||
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
|
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
@ -29,7 +29,7 @@ jobs:
|
||||||
|
|
||||||
- name: setup node
|
- name: setup node
|
||||||
id: setup-node
|
id: setup-node
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
@ -66,7 +66,7 @@ jobs:
|
||||||
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
|
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Check version
|
- name: Check version
|
||||||
run: |
|
run: |
|
||||||
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then
|
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then
|
||||||
|
|
|
@ -12,7 +12,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Check
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
counter=0
|
counter=0
|
||||||
|
|
|
@ -10,7 +10,7 @@ jobs:
|
||||||
check_copyright_year:
|
check_copyright_year:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
- run: |
|
- run: |
|
||||||
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
|
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
|
||||||
echo "Please change copyright year!"
|
echo "Please change copyright year!"
|
||||||
|
|
|
@ -28,7 +28,7 @@ jobs:
|
||||||
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
|
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Check allowed users
|
- name: Check allowed users
|
||||||
id: check-allowed-users
|
id: check-allowed-users
|
||||||
|
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
platform=${{ matrix.platform }}
|
platform=${{ matrix.platform }}
|
||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
|
|
|
@ -32,7 +32,7 @@ jobs:
|
||||||
platform=${{ matrix.platform }}
|
platform=${{ matrix.platform }}
|
||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
||||||
DOCKER_CONTENT_TRUST: 1
|
DOCKER_CONTENT_TRUST: 1
|
||||||
DOCKLE_VERSION: 0.4.14
|
DOCKLE_VERSION: 0.4.14
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
- name: Download and install dockle v${{ env.DOCKLE_VERSION }}
|
- name: Download and install dockle v${{ env.DOCKLE_VERSION }}
|
||||||
run: |
|
run: |
|
||||||
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"
|
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"
|
||||||
|
|
|
@ -30,14 +30,14 @@ jobs:
|
||||||
ref: refs/pull/${{ github.event.number }}/merge
|
ref: refs/pull/${{ github.event.number }}/merge
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
ref: ${{ matrix.ref }}
|
ref: ${{ matrix.ref }}
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -36,12 +36,12 @@ jobs:
|
||||||
pnpm_install:
|
pnpm_install:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
- uses: actions/setup-node@v4.1.0
|
- uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
@ -67,19 +67,19 @@ jobs:
|
||||||
eslint-cache-version: v1
|
eslint-cache-version: v1
|
||||||
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
|
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
- uses: actions/setup-node@v4.1.0
|
- uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
- run: pnpm i --frozen-lockfile
|
- run: pnpm i --frozen-lockfile
|
||||||
- name: Restore eslint cache
|
- name: Restore eslint cache
|
||||||
uses: actions/cache@v4.2.0
|
uses: actions/cache@v4.2.1
|
||||||
with:
|
with:
|
||||||
path: ${{ env.eslint-cache-path }}
|
path: ${{ env.eslint-cache-path }}
|
||||||
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
|
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
|
||||||
|
@ -97,12 +97,12 @@ jobs:
|
||||||
- sw
|
- sw
|
||||||
- misskey-js
|
- misskey-js
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
- uses: actions/setup-node@v4.1.0
|
- uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -18,12 +18,12 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
- uses: actions/setup-node@v4.1.0
|
- uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
# If someone with write access comments "/ok-to-test" on a pull request, emit a repository_dispatch event
|
|
||||||
name: Ok To Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ok-to-test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
# Only run for PRs, not issue comments
|
|
||||||
if: ${{ github.event.issue.pull_request }}
|
|
||||||
steps:
|
|
||||||
# Generate a GitHub App installation access token from an App ID and private key
|
|
||||||
# To create a new GitHub App:
|
|
||||||
# https://developer.github.com/apps/building-github-apps/creating-a-github-app/
|
|
||||||
# See app.yml for an example app manifest
|
|
||||||
- name: Generate token
|
|
||||||
id: generate_token
|
|
||||||
uses: tibdex/github-app-token@v2
|
|
||||||
with:
|
|
||||||
app_id: ${{ secrets.DEPLOYBOT_APP_ID }}
|
|
||||||
private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Slash Command Dispatch
|
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ steps.generate_token.outputs.token }}
|
|
||||||
with:
|
|
||||||
token: ${{ env.TOKEN }} # GitHub App installation access token
|
|
||||||
# token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # PAT or OAuth token will also work
|
|
||||||
reaction-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
issue-type: pull-request
|
|
||||||
commands: deploy
|
|
||||||
named-args: true
|
|
||||||
permission: write
|
|
|
@ -23,13 +23,13 @@ jobs:
|
||||||
node-version: [22.11.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
# Run secret-dependent integration tests only after /deploy approval
|
|
||||||
on:
|
|
||||||
repository_dispatch:
|
|
||||||
types: [deploy-command]
|
|
||||||
|
|
||||||
name: Deploy preview environment
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# Repo owner has commented /deploy on a (fork-based) pull request
|
|
||||||
deploy-preview-environment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if:
|
|
||||||
github.event.client_payload.slash_command.sha != '' &&
|
|
||||||
contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
|
|
||||||
steps:
|
|
||||||
- uses: actions/github-script@v7.0.1
|
|
||||||
id: check-id
|
|
||||||
env:
|
|
||||||
number: ${{ github.event.client_payload.pull_request.number }}
|
|
||||||
job: ${{ github.job }}
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
result-encoding: string
|
|
||||||
script: |
|
|
||||||
const { data: pull } = await github.rest.pulls.get({
|
|
||||||
...context.repo,
|
|
||||||
pull_number: process.env.number
|
|
||||||
});
|
|
||||||
const ref = pull.head.sha;
|
|
||||||
|
|
||||||
const { data: checks } = await github.rest.checks.listForRef({
|
|
||||||
...context.repo,
|
|
||||||
ref
|
|
||||||
});
|
|
||||||
|
|
||||||
const check = checks.check_runs.filter(c => c.name === process.env.job);
|
|
||||||
|
|
||||||
return check[0].id;
|
|
||||||
|
|
||||||
- uses: actions/github-script@v7.0.1
|
|
||||||
env:
|
|
||||||
check_id: ${{ steps.check-id.outputs.result }}
|
|
||||||
details_url: ${{ github.server_url }}/${{ github.repository }}/runs/${{ github.run_id }}
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
script: |
|
|
||||||
await github.rest.checks.update({
|
|
||||||
...context.repo,
|
|
||||||
check_run_id: process.env.check_id,
|
|
||||||
status: 'in_progress',
|
|
||||||
details_url: process.env.details_url
|
|
||||||
});
|
|
||||||
|
|
||||||
# Check out merge commit
|
|
||||||
- name: Fork based /deploy checkout
|
|
||||||
uses: actions/checkout@v4.1.1
|
|
||||||
with:
|
|
||||||
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
|
|
||||||
|
|
||||||
# <insert integration tests needing secrets>
|
|
||||||
- name: Context
|
|
||||||
uses: okteto/context@latest
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.OKTETO_TOKEN }}
|
|
||||||
|
|
||||||
- name: Deploy preview environment
|
|
||||||
uses: ikuradon/deploy-preview@latest
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
name: pr-${{ github.event.client_payload.pull_request.number }}-syuilo
|
|
||||||
timeout: 15m
|
|
||||||
|
|
||||||
# Update check run called "integration-fork"
|
|
||||||
- uses: actions/github-script@v7.0.1
|
|
||||||
id: update-check-run
|
|
||||||
if: ${{ always() }}
|
|
||||||
env:
|
|
||||||
# Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
|
|
||||||
conclusion: ${{ job.status }}
|
|
||||||
check_id: ${{ steps.check-id.outputs.result }}
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
script: |
|
|
||||||
const { data: result } = await github.rest.checks.update({
|
|
||||||
...context.repo,
|
|
||||||
check_run_id: process.env.check_id,
|
|
||||||
status: 'completed',
|
|
||||||
conclusion: process.env.conclusion
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
|
@ -1,54 +0,0 @@
|
||||||
# file: .github/workflows/preview-closed.yaml
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- closed
|
|
||||||
|
|
||||||
name: Destroy preview environment
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
destroy-preview-environment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/github-script@v7.0.1
|
|
||||||
id: check-conclusion
|
|
||||||
env:
|
|
||||||
number: ${{ github.event.number }}
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
result-encoding: string
|
|
||||||
script: |
|
|
||||||
const { data: pull } = await github.rest.pulls.get({
|
|
||||||
...context.repo,
|
|
||||||
pull_number: process.env.number
|
|
||||||
});
|
|
||||||
const ref = pull.head.sha;
|
|
||||||
|
|
||||||
const { data: checks } = await github.rest.checks.listForRef({
|
|
||||||
...context.repo,
|
|
||||||
ref
|
|
||||||
});
|
|
||||||
|
|
||||||
const check = checks.check_runs.filter(c => c.name === 'deploy-preview-environment');
|
|
||||||
|
|
||||||
if (check.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data: result } = await github.rest.checks.get({
|
|
||||||
...context.repo,
|
|
||||||
check_run_id: check[0].id,
|
|
||||||
});
|
|
||||||
|
|
||||||
return result.conclusion;
|
|
||||||
- name: Context
|
|
||||||
if: steps.check-conclusion.outputs.result == 'success'
|
|
||||||
uses: okteto/context@latest
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.OKTETO_TOKEN }}
|
|
||||||
|
|
||||||
- name: Destroy preview environment
|
|
||||||
if: steps.check-conclusion.outputs.result == 'success'
|
|
||||||
uses: okteto/destroy-preview@latest
|
|
||||||
with:
|
|
||||||
name: pr-${{ github.event.number }}-syuilo
|
|
|
@ -26,12 +26,12 @@ jobs:
|
||||||
NODE_OPTIONS: "--max_old_space_size=7168"
|
NODE_OPTIONS: "--max_old_space_size=7168"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
if: github.event_name != 'pull_request_target'
|
if: github.event_name != 'pull_request_target'
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
if: github.event_name == 'pull_request_target'
|
if: github.event_name == 'pull_request_target'
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
@ -46,7 +46,7 @@ jobs:
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- name: Use Node.js 20.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -45,7 +45,7 @@ jobs:
|
||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
|
@ -66,7 +66,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
@ -108,13 +108,13 @@ jobs:
|
||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -47,7 +47,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -36,13 +36,13 @@ jobs:
|
||||||
node-version: [22.11.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
@ -86,7 +86,7 @@ jobs:
|
||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
# https://github.com/cypress-io/cypress-docker-images/issues/150
|
# https://github.com/cypress-io/cypress-docker-images/issues/150
|
||||||
|
@ -98,7 +98,7 @@ jobs:
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -31,12 +31,12 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
|
|
||||||
- name: Setup Node.js ${{ matrix.node-version }}
|
- name: Setup Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -21,13 +21,13 @@ jobs:
|
||||||
node-version: [22.11.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -25,13 +25,13 @@ jobs:
|
||||||
node-version: [22.11.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.2.2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.1.0
|
uses: actions/setup-node@v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
42
CHANGELOG.md
42
CHANGELOG.md
|
@ -1,7 +1,36 @@
|
||||||
## 2025.2.0
|
## 2025.2.1
|
||||||
|
|
||||||
### Note
|
### General
|
||||||
- ページの「ソースを見る」機能は削除されました
|
- Feat: アクセストークン発行時に通知するように
|
||||||
|
- 依存関係の更新
|
||||||
|
|
||||||
|
### Client
|
||||||
|
- Feat: 投稿フォームで画像をプレビュー可能に
|
||||||
|
- Enhance: 投稿フォームの「迷惑になる可能性があります」のダイアログを表示する条件においてCWを考慮するように
|
||||||
|
- Enhance: アンテナ、リスト等の名前をカラム名のデフォルト値にするように `#13992`
|
||||||
|
- Enhance: クライアントエラー画面の多言語対応
|
||||||
|
- Enhance: 開発者モードでメニューからファイルIDをコピー出来るように `#15441'
|
||||||
|
- Enhance: ノートに埋め込まれたメディアのコンテキストメニューから管理者用のファイル管理画面を開けるように ( #15440 )
|
||||||
|
- Enhance: リアクションする際に確認ダイアログを表示できるように
|
||||||
|
- Enhance: CWの注釈で入力済みの文字数を表示
|
||||||
|
- Fix: コンディショナルロールを手動で割り当てできる導線を削除 `#13529`
|
||||||
|
- Fix: 埋め込みプレイヤーから外部ページに移動できない問題を修正
|
||||||
|
- Fix: Play の再読込時に UI が以前の状態を引き継いでしまう問題を修正 `#14378`
|
||||||
|
- Fix: カスタム絵文字管理画面(beta)にてisSensitive/localOnlyの絞り込みが上手くいかない問題の修正 ( #15445 )
|
||||||
|
- Fix: CWの注釈が100文字を超えている場合、ノート投稿ボタンを非アクティブに
|
||||||
|
|
||||||
|
### Server
|
||||||
|
- Enhance: 成り済まし対策として、ActivityPub照会された時にリモートのリダイレクトを拒否できるように (config.disallowExternalApRedirect)
|
||||||
|
- Enhance: スレッドミュートにおいて、リノート、引用、リアクションの通知もミュートするように
|
||||||
|
- なお、以下のケースでは引き続き通知がミュートされません。(ミュートを行っているユーザーをAとします)
|
||||||
|
- ミュート対象ノートを、当該スレッドの外にあるAへの返信/メンション付きノートにおいて引用する
|
||||||
|
- Fix: `following/invalidate`でフォロワーを解除しようとしているユーザーの情報を返すように
|
||||||
|
- Fix: オブジェクトストレージの設定でPrefixを設定していなかった場合nullまたは空文字になる問題を修正
|
||||||
|
- Fix: pgroongaでの検索時にはじめのキーワードのみが検索に使用される問題を修正
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/886)
|
||||||
|
- Fix: メールアドレスの形式が正しくなければ以降の処理を行わないように
|
||||||
|
|
||||||
|
## 2025.2.0
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- Fix: Docker のビルドに失敗する問題を修正
|
- Fix: Docker のビルドに失敗する問題を修正
|
||||||
|
@ -13,12 +42,13 @@
|
||||||
- Fix: データセーバー有効時にもユーザーページの「ファイル」タブで画像が読み込まれてしまう問題を修正
|
- Fix: データセーバー有効時にもユーザーページの「ファイル」タブで画像が読み込まれてしまう問題を修正
|
||||||
- Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正
|
- Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正
|
||||||
- Fix: ページのURLにスラッシュが含まれている場合にページが正しく表示されない問題を修正
|
- Fix: ページのURLにスラッシュが含まれている場合にページが正しく表示されない問題を修正
|
||||||
|
- Fix: デッキのプロファイルが新規作成できない問題を修正
|
||||||
|
- Fix: セキュリティに関する修正
|
||||||
- ローカライゼーションの更新
|
- ローカライゼーションの更新
|
||||||
|
- Playが実装されたため、ページ機能の「ソースを見る」は削除されました
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Enhance: スレッドミュートにおいて、リノート、引用、リアクションの通知もミュートするように
|
- Enhance: ページのURLに使用可能な文字を限定するように
|
||||||
- なお、以下のケースでは引き続き通知がミュートされません。(ミュートを行っているユーザーをAとします)
|
|
||||||
- ミュート対象ノートを、当該スレッドの外にあるAへの返信/メンション付きノートにおいて引用する
|
|
||||||
- Fix: 個別お知らせページのmetaタグ出力の条件が間違っていたのを修正
|
- Fix: 個別お知らせページのmetaタグ出力の条件が間違っていたのを修正
|
||||||
|
|
||||||
## 2025.1.0
|
## 2025.1.0
|
||||||
|
|
|
@ -1460,9 +1460,6 @@ _pages:
|
||||||
newPage: "أنشئ صفحة جديدة"
|
newPage: "أنشئ صفحة جديدة"
|
||||||
editPage: "عدّل الصفحة"
|
editPage: "عدّل الصفحة"
|
||||||
readPage: "نُشّط عرض المصدر"
|
readPage: "نُشّط عرض المصدر"
|
||||||
created: "نجح إنشاء الصفحة"
|
|
||||||
updated: "نجح تعديل الصفحة"
|
|
||||||
deleted: "نجح حذف الصفحة"
|
|
||||||
pageSetting: "إعدادات الصفحة"
|
pageSetting: "إعدادات الصفحة"
|
||||||
nameAlreadyExists: "رابط الصفحة موجود مسبقًا"
|
nameAlreadyExists: "رابط الصفحة موجود مسبقًا"
|
||||||
invalidNameTitle: "رابط الصفحة ليس صالحًا"
|
invalidNameTitle: "رابط الصفحة ليس صالحًا"
|
||||||
|
|
|
@ -1237,9 +1237,6 @@ _pages:
|
||||||
newPage: "নতুন পৃষ্ঠা বানান"
|
newPage: "নতুন পৃষ্ঠা বানান"
|
||||||
editPage: "পৃষ্ঠাটি সম্পাদনা করুন"
|
editPage: "পৃষ্ঠাটি সম্পাদনা করুন"
|
||||||
readPage: "উৎস দেখছেন"
|
readPage: "উৎস দেখছেন"
|
||||||
created: "পৃষ্ঠা তৈরি করা হয়েছে"
|
|
||||||
updated: "পৃষ্ঠা সম্পাদনা করা হয়েছে"
|
|
||||||
deleted: "পৃষ্ঠা মুছে ফেলা হয়েছে"
|
|
||||||
pageSetting: "পৃষ্ঠার সেটিংস"
|
pageSetting: "পৃষ্ঠার সেটিংস"
|
||||||
nameAlreadyExists: "পৃষ্ঠার URLটি ইতিমধ্যেই ব্যাবহার করা হয়েছে"
|
nameAlreadyExists: "পৃষ্ঠার URLটি ইতিমধ্যেই ব্যাবহার করা হয়েছে"
|
||||||
invalidNameTitle: "পৃষ্ঠার URL অবৈধ"
|
invalidNameTitle: "পৃষ্ঠার URL অবৈধ"
|
||||||
|
|
|
@ -2365,9 +2365,6 @@ _pages:
|
||||||
newPage: "pa"
|
newPage: "pa"
|
||||||
editPage: "Editar la pàgina"
|
editPage: "Editar la pàgina"
|
||||||
readPage: "Veure el codi font d'aquesta pàgina"
|
readPage: "Veure el codi font d'aquesta pàgina"
|
||||||
created: "La pàgina ha sigut creada correctament"
|
|
||||||
updated: "La pàgina s'ha editat correctament"
|
|
||||||
deleted: "La pàgina s'ha esborrat sense problemes"
|
|
||||||
pageSetting: "Configuració de la pàgina"
|
pageSetting: "Configuració de la pàgina"
|
||||||
nameAlreadyExists: "L'adreça URL de la pàgina ja existeix"
|
nameAlreadyExists: "L'adreça URL de la pàgina ja existeix"
|
||||||
invalidNameTitle: "L'adreça URL de la pàgina no és vàlida"
|
invalidNameTitle: "L'adreça URL de la pàgina no és vàlida"
|
||||||
|
|
|
@ -1883,9 +1883,6 @@ _pages:
|
||||||
newPage: "Vytvořit novou stránku"
|
newPage: "Vytvořit novou stránku"
|
||||||
editPage: "Upravit stránku"
|
editPage: "Upravit stránku"
|
||||||
readPage: "Prohlížení zdroje této stránky"
|
readPage: "Prohlížení zdroje této stránky"
|
||||||
created: "Stránka byla úspěšně vytvořena"
|
|
||||||
updated: "Stránka byla úspěšně aktualizována"
|
|
||||||
deleted: "Stránka byla úspěšně smazána"
|
|
||||||
pageSetting: "Nastavení stránky"
|
pageSetting: "Nastavení stránky"
|
||||||
nameAlreadyExists: "Zadaná adresa URL stránky již existuje"
|
nameAlreadyExists: "Zadaná adresa URL stránky již existuje"
|
||||||
invalidNameTitle: "Zadaná adresa URL stránky je neplatná"
|
invalidNameTitle: "Zadaná adresa URL stránky je neplatná"
|
||||||
|
|
|
@ -2277,9 +2277,6 @@ _pages:
|
||||||
newPage: "Seite erstellen"
|
newPage: "Seite erstellen"
|
||||||
editPage: "Seite bearbeiten"
|
editPage: "Seite bearbeiten"
|
||||||
readPage: "Quelltextansicht"
|
readPage: "Quelltextansicht"
|
||||||
created: "Seite erfolgreich erstellt"
|
|
||||||
updated: "Seite erfolgreich aktualisiert"
|
|
||||||
deleted: "Seite erfolgreich gelöscht"
|
|
||||||
pageSetting: "Seiteneinstellungen"
|
pageSetting: "Seiteneinstellungen"
|
||||||
nameAlreadyExists: "Die angegebene Seiten-URL existiert bereits"
|
nameAlreadyExists: "Die angegebene Seiten-URL existiert bereits"
|
||||||
invalidNameTitle: "Die angegebene Seiten-URL ist ungültig"
|
invalidNameTitle: "Die angegebene Seiten-URL ist ungültig"
|
||||||
|
|
|
@ -2365,9 +2365,6 @@ _pages:
|
||||||
newPage: "Create a new Page"
|
newPage: "Create a new Page"
|
||||||
editPage: "Edit this Page"
|
editPage: "Edit this Page"
|
||||||
readPage: "Viewing this Page's source"
|
readPage: "Viewing this Page's source"
|
||||||
created: "Page successfully created"
|
|
||||||
updated: "Page successfully edited"
|
|
||||||
deleted: "Page successfully deleted"
|
|
||||||
pageSetting: "Page settings"
|
pageSetting: "Page settings"
|
||||||
nameAlreadyExists: "The specified Page URL already exists"
|
nameAlreadyExists: "The specified Page URL already exists"
|
||||||
invalidNameTitle: "The specified Page URL is invalid"
|
invalidNameTitle: "The specified Page URL is invalid"
|
||||||
|
@ -2775,6 +2772,7 @@ _customEmojisManager:
|
||||||
confirmUpdateEmojisDescription: "Update {count} Emoji(s). Are you sure to continue?"
|
confirmUpdateEmojisDescription: "Update {count} Emoji(s). Are you sure to continue?"
|
||||||
confirmDeleteEmojisDescription: "Delete checked {count} Emoji(s). Are you sure to continue?"
|
confirmDeleteEmojisDescription: "Delete checked {count} Emoji(s). Are you sure to continue?"
|
||||||
confirmResetDescription: ""
|
confirmResetDescription: ""
|
||||||
|
confirmMovePageDesciption: "Changes have been made to the Emojis on this page.\nIf you leave the page without saving, all changes made on this page will be discarded."
|
||||||
dialogSelectRoleTitle: "Search by roll set in Emojis"
|
dialogSelectRoleTitle: "Search by roll set in Emojis"
|
||||||
_register:
|
_register:
|
||||||
uploadSettingTitle: "Upload settings"
|
uploadSettingTitle: "Upload settings"
|
||||||
|
|
|
@ -2294,9 +2294,6 @@ _pages:
|
||||||
newPage: "Crear página"
|
newPage: "Crear página"
|
||||||
editPage: "Editar página"
|
editPage: "Editar página"
|
||||||
readPage: "Viendo la fuente"
|
readPage: "Viendo la fuente"
|
||||||
created: "La página fue creada"
|
|
||||||
updated: "La página fue actualizada"
|
|
||||||
deleted: "La página borrada"
|
|
||||||
pageSetting: "Configurar página"
|
pageSetting: "Configurar página"
|
||||||
nameAlreadyExists: "La URL de la página especificada ya existe"
|
nameAlreadyExists: "La URL de la página especificada ya existe"
|
||||||
invalidNameTitle: "URL inválida"
|
invalidNameTitle: "URL inválida"
|
||||||
|
|
|
@ -2118,9 +2118,6 @@ _pages:
|
||||||
newPage: "Créer une page"
|
newPage: "Créer une page"
|
||||||
editPage: "Modifier une page"
|
editPage: "Modifier une page"
|
||||||
readPage: "Affichage de la source en cours"
|
readPage: "Affichage de la source en cours"
|
||||||
created: "La page a été créée !"
|
|
||||||
updated: "La page a été mise à jour !"
|
|
||||||
deleted: "La page a été supprimée"
|
|
||||||
pageSetting: "Paramètres de la Page"
|
pageSetting: "Paramètres de la Page"
|
||||||
nameAlreadyExists: "L'URL de page spécifiée existe déjà"
|
nameAlreadyExists: "L'URL de page spécifiée existe déjà"
|
||||||
invalidNameTitle: "L'URL de page spécifiée n’est pas valide"
|
invalidNameTitle: "L'URL de page spécifiée n’est pas valide"
|
||||||
|
|
|
@ -2285,9 +2285,6 @@ _pages:
|
||||||
newPage: "Buat halaman baru"
|
newPage: "Buat halaman baru"
|
||||||
editPage: "Sunting halaman"
|
editPage: "Sunting halaman"
|
||||||
readPage: "Lihat sumber kode aktif"
|
readPage: "Lihat sumber kode aktif"
|
||||||
created: "Halaman berhasil dibuat"
|
|
||||||
updated: "Halaman berhasil diperbaharui!"
|
|
||||||
deleted: "Halaman telah dihapus"
|
|
||||||
pageSetting: "Pengaturan Halaman"
|
pageSetting: "Pengaturan Halaman"
|
||||||
nameAlreadyExists: "URL Halaman yang ditentukan sudah ada"
|
nameAlreadyExists: "URL Halaman yang ditentukan sudah ada"
|
||||||
invalidNameTitle: "URL Halaman yang ditentukan tidak valid"
|
invalidNameTitle: "URL Halaman yang ditentukan tidak valid"
|
||||||
|
|
|
@ -4195,7 +4195,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"invalidParamError": string;
|
"invalidParamError": string;
|
||||||
/**
|
/**
|
||||||
* リクエストパラメータに問題があります。通常これはバグですが、入力した文字数が多すぎる等の可能性もあります。
|
* リクエストパラメータに問題があります。通常これはバグですが、入力した文字数が多すぎる・許可されていない文字を入力している等の可能性もあります。
|
||||||
*/
|
*/
|
||||||
"invalidParamErrorDescription": string;
|
"invalidParamErrorDescription": string;
|
||||||
/**
|
/**
|
||||||
|
@ -5254,6 +5254,14 @@ export interface Locale extends ILocale {
|
||||||
* このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。
|
* このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。
|
||||||
*/
|
*/
|
||||||
"federationDisabled": string;
|
"federationDisabled": string;
|
||||||
|
/**
|
||||||
|
* リアクションする際に確認する
|
||||||
|
*/
|
||||||
|
"confirmOnReact": string;
|
||||||
|
/**
|
||||||
|
* " {emoji} " をリアクションしますか?
|
||||||
|
*/
|
||||||
|
"reactAreYouSure": ParameterizedString<"emoji">;
|
||||||
"_accountSettings": {
|
"_accountSettings": {
|
||||||
/**
|
/**
|
||||||
* コンテンツの表示にログインを必須にする
|
* コンテンツの表示にログインを必須にする
|
||||||
|
@ -9180,18 +9188,6 @@ export interface Locale extends ILocale {
|
||||||
* ソースを表示中
|
* ソースを表示中
|
||||||
*/
|
*/
|
||||||
"readPage": string;
|
"readPage": string;
|
||||||
/**
|
|
||||||
* ページを作成しました
|
|
||||||
*/
|
|
||||||
"created": string;
|
|
||||||
/**
|
|
||||||
* ページを更新しました
|
|
||||||
*/
|
|
||||||
"updated": string;
|
|
||||||
/**
|
|
||||||
* ページを削除しました
|
|
||||||
*/
|
|
||||||
"deleted": string;
|
|
||||||
/**
|
/**
|
||||||
* ページ設定
|
* ページ設定
|
||||||
*/
|
*/
|
||||||
|
@ -9484,6 +9480,14 @@ export interface Locale extends ILocale {
|
||||||
* ログインがありました
|
* ログインがありました
|
||||||
*/
|
*/
|
||||||
"login": string;
|
"login": string;
|
||||||
|
/**
|
||||||
|
* アクセストークンが作成されました
|
||||||
|
*/
|
||||||
|
"createToken": string;
|
||||||
|
/**
|
||||||
|
* 心当たりがない場合は「{text}」を通じてアクセストークンを削除してください。
|
||||||
|
*/
|
||||||
|
"createTokenDescription": ParameterizedString<"text">;
|
||||||
"_types": {
|
"_types": {
|
||||||
/**
|
/**
|
||||||
* すべて
|
* すべて
|
||||||
|
@ -10892,13 +10896,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"title": string;
|
"title": string;
|
||||||
/**
|
/**
|
||||||
* このサーバーと通信することはできましたが、得られたデータが不正なものでした。
|
* このサーバーと通信することはできましたが、得られたデータが不正なものでした。第三者のサーバーを介してリモートのコンテンツを照会している場合は、発信元のサーバーで取得できるURIを使用して照会し直してください。
|
||||||
*/
|
|
||||||
"description": string;
|
|
||||||
};
|
|
||||||
"_responseInvalidIdHostNotMatch": {
|
|
||||||
/**
|
|
||||||
* 入力されたURIのドメインと最終的に得られたURIのドメインとが異なります。第三者のサーバーを介してリモートのコンテンツを照会している場合は、発信元のサーバーで取得できるURIを使用して照会し直してください。
|
|
||||||
*/
|
*/
|
||||||
"description": string;
|
"description": string;
|
||||||
};
|
};
|
||||||
|
@ -10956,6 +10954,52 @@ export interface Locale extends ILocale {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
"_bootErrors": {
|
||||||
|
/**
|
||||||
|
* 読み込みに失敗しました
|
||||||
|
*/
|
||||||
|
"title": string;
|
||||||
|
/**
|
||||||
|
* 少し待ってからリロードしてもまだ問題が解決されない場合、以下のError IDを添えてサーバー管理者に連絡してください。
|
||||||
|
*/
|
||||||
|
"serverError": string;
|
||||||
|
/**
|
||||||
|
* 以下を行うと解決する可能性があります。
|
||||||
|
*/
|
||||||
|
"solution": string;
|
||||||
|
/**
|
||||||
|
* ブラウザおよびOSを最新バージョンに更新する
|
||||||
|
*/
|
||||||
|
"solution1": string;
|
||||||
|
/**
|
||||||
|
* アドブロッカーを無効にする
|
||||||
|
*/
|
||||||
|
"solution2": string;
|
||||||
|
/**
|
||||||
|
* ブラウザのキャッシュをクリアする
|
||||||
|
*/
|
||||||
|
"solution3": string;
|
||||||
|
/**
|
||||||
|
* (Tor Browser) dom.webaudio.enabledをtrueに設定する
|
||||||
|
*/
|
||||||
|
"solution4": string;
|
||||||
|
/**
|
||||||
|
* その他のオプション
|
||||||
|
*/
|
||||||
|
"otherOption": string;
|
||||||
|
/**
|
||||||
|
* クライアント設定とキャッシュを削除
|
||||||
|
*/
|
||||||
|
"otherOption1": string;
|
||||||
|
/**
|
||||||
|
* 簡易クライアントを起動
|
||||||
|
*/
|
||||||
|
"otherOption2": string;
|
||||||
|
/**
|
||||||
|
* 修復ツールを起動
|
||||||
|
*/
|
||||||
|
"otherOption3": string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
declare const locales: {
|
declare const locales: {
|
||||||
[lang: string]: Locale;
|
[lang: string]: Locale;
|
||||||
|
|
|
@ -2365,9 +2365,6 @@ _pages:
|
||||||
newPage: "Crea pagina"
|
newPage: "Crea pagina"
|
||||||
editPage: "Modifica pagina"
|
editPage: "Modifica pagina"
|
||||||
readPage: "Visualizzando fonte "
|
readPage: "Visualizzando fonte "
|
||||||
created: "Pagina creata!"
|
|
||||||
updated: "Pagina aggiornata con successo!"
|
|
||||||
deleted: "Pagina eliminata"
|
|
||||||
pageSetting: "Impostazioni pagina"
|
pageSetting: "Impostazioni pagina"
|
||||||
nameAlreadyExists: "Esiste già una pagina con lo stesso URL."
|
nameAlreadyExists: "Esiste già una pagina con lo stesso URL."
|
||||||
invalidNameTitle: "L'URL di pagina definito non è valido"
|
invalidNameTitle: "L'URL di pagina definito non è valido"
|
||||||
|
|
|
@ -1044,7 +1044,7 @@ youCannotCreateAnymore: "これ以上作成することはできません。"
|
||||||
cannotPerformTemporary: "一時的に利用できません"
|
cannotPerformTemporary: "一時的に利用できません"
|
||||||
cannotPerformTemporaryDescription: "操作回数が制限を超過するため一時的に利用できません。しばらく時間を置いてから再度お試しください。"
|
cannotPerformTemporaryDescription: "操作回数が制限を超過するため一時的に利用できません。しばらく時間を置いてから再度お試しください。"
|
||||||
invalidParamError: "パラメータエラー"
|
invalidParamError: "パラメータエラー"
|
||||||
invalidParamErrorDescription: "リクエストパラメータに問題があります。通常これはバグですが、入力した文字数が多すぎる等の可能性もあります。"
|
invalidParamErrorDescription: "リクエストパラメータに問題があります。通常これはバグですが、入力した文字数が多すぎる・許可されていない文字を入力している等の可能性もあります。"
|
||||||
permissionDeniedError: "操作が拒否されました"
|
permissionDeniedError: "操作が拒否されました"
|
||||||
permissionDeniedErrorDescription: "このアカウントにはこの操作を行うための権限がありません。"
|
permissionDeniedErrorDescription: "このアカウントにはこの操作を行うための権限がありません。"
|
||||||
preset: "プリセット"
|
preset: "プリセット"
|
||||||
|
@ -1309,6 +1309,8 @@ availableRoles: "利用可能なロール"
|
||||||
acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。"
|
acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。"
|
||||||
federationSpecified: "このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。"
|
federationSpecified: "このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。"
|
||||||
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
|
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
|
||||||
|
confirmOnReact: "リアクションする際に確認する"
|
||||||
|
reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
|
||||||
|
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
||||||
|
@ -2422,9 +2424,6 @@ _pages:
|
||||||
newPage: "ページの作成"
|
newPage: "ページの作成"
|
||||||
editPage: "ページの編集"
|
editPage: "ページの編集"
|
||||||
readPage: "ソースを表示中"
|
readPage: "ソースを表示中"
|
||||||
created: "ページを作成しました"
|
|
||||||
updated: "ページを更新しました"
|
|
||||||
deleted: "ページを削除しました"
|
|
||||||
pageSetting: "ページ設定"
|
pageSetting: "ページ設定"
|
||||||
nameAlreadyExists: "指定されたページURLは既に存在しています"
|
nameAlreadyExists: "指定されたページURLは既に存在しています"
|
||||||
invalidNameTitle: "不正なページURLです"
|
invalidNameTitle: "不正なページURLです"
|
||||||
|
@ -2503,6 +2502,8 @@ _notification:
|
||||||
flushNotification: "通知の履歴をリセットする"
|
flushNotification: "通知の履歴をリセットする"
|
||||||
exportOfXCompleted: "{x}のエクスポートが完了しました"
|
exportOfXCompleted: "{x}のエクスポートが完了しました"
|
||||||
login: "ログインがありました"
|
login: "ログインがありました"
|
||||||
|
createToken: "アクセストークンが作成されました"
|
||||||
|
createTokenDescription: "心当たりがない場合は「{text}」を通じてアクセストークンを削除してください。"
|
||||||
|
|
||||||
_types:
|
_types:
|
||||||
all: "すべて"
|
all: "すべて"
|
||||||
|
@ -2910,9 +2911,7 @@ _remoteLookupErrors:
|
||||||
description: "このサーバーとの通信に失敗しました。相手サーバーがダウンしている可能性があります。また、不正なURIや存在しないURIを入力していないか確認してください。"
|
description: "このサーバーとの通信に失敗しました。相手サーバーがダウンしている可能性があります。また、不正なURIや存在しないURIを入力していないか確認してください。"
|
||||||
_responseInvalid:
|
_responseInvalid:
|
||||||
title: "レスポンスが不正です"
|
title: "レスポンスが不正です"
|
||||||
description: "このサーバーと通信することはできましたが、得られたデータが不正なものでした。"
|
description: "このサーバーと通信することはできましたが、得られたデータが不正なものでした。第三者のサーバーを介してリモートのコンテンツを照会している場合は、発信元のサーバーで取得できるURIを使用して照会し直してください。"
|
||||||
_responseInvalidIdHostNotMatch:
|
|
||||||
description: "入力されたURIのドメインと最終的に得られたURIのドメインとが異なります。第三者のサーバーを介してリモートのコンテンツを照会している場合は、発信元のサーバーで取得できるURIを使用して照会し直してください。"
|
|
||||||
_noSuchObject:
|
_noSuchObject:
|
||||||
title: "見つかりません"
|
title: "見つかりません"
|
||||||
description: "要求されたリソースは見つかりませんでした。URIをもう一度お確かめください。"
|
description: "要求されたリソースは見つかりませんでした。URIをもう一度お確かめください。"
|
||||||
|
@ -2930,3 +2929,16 @@ _captcha:
|
||||||
_unknown:
|
_unknown:
|
||||||
title: "CAPTCHAエラー"
|
title: "CAPTCHAエラー"
|
||||||
text: "想定外のエラーが発生しました。"
|
text: "想定外のエラーが発生しました。"
|
||||||
|
|
||||||
|
_bootErrors:
|
||||||
|
title: "読み込みに失敗しました"
|
||||||
|
serverError: "少し待ってからリロードしてもまだ問題が解決されない場合、以下のError IDを添えてサーバー管理者に連絡してください。"
|
||||||
|
solution: "以下を行うと解決する可能性があります。"
|
||||||
|
solution1: "ブラウザおよびOSを最新バージョンに更新する"
|
||||||
|
solution2: "アドブロッカーを無効にする"
|
||||||
|
solution3: "ブラウザのキャッシュをクリアする"
|
||||||
|
solution4: "(Tor Browser) dom.webaudio.enabledをtrueに設定する"
|
||||||
|
otherOption: "その他のオプション"
|
||||||
|
otherOption1: "クライアント設定とキャッシュを削除"
|
||||||
|
otherOption2: "簡易クライアントを起動"
|
||||||
|
otherOption3: "修復ツールを起動"
|
||||||
|
|
|
@ -2357,9 +2357,6 @@ _pages:
|
||||||
newPage: "ページを作る"
|
newPage: "ページを作る"
|
||||||
editPage: "ページの編集"
|
editPage: "ページの編集"
|
||||||
readPage: "ソースを表示中"
|
readPage: "ソースを表示中"
|
||||||
created: "ページを作成したで"
|
|
||||||
updated: "ページを更新したで"
|
|
||||||
deleted: "ページを削除したで"
|
|
||||||
pageSetting: "ページ設定"
|
pageSetting: "ページ設定"
|
||||||
nameAlreadyExists: "指定されたページURLはもうあるみたいや"
|
nameAlreadyExists: "指定されたページURLはもうあるみたいや"
|
||||||
invalidNameTitle: "正しくないページURLみたいやで"
|
invalidNameTitle: "正しくないページURLみたいやで"
|
||||||
|
|
|
@ -2365,9 +2365,6 @@ _pages:
|
||||||
newPage: "페이지 만들기"
|
newPage: "페이지 만들기"
|
||||||
editPage: "페이지 수정"
|
editPage: "페이지 수정"
|
||||||
readPage: "소스 표시 중"
|
readPage: "소스 표시 중"
|
||||||
created: "페이지를 만들었습니다"
|
|
||||||
updated: "페이지를 수정했습니다"
|
|
||||||
deleted: "페이지가 삭제되었습니다"
|
|
||||||
pageSetting: "페이지 설정"
|
pageSetting: "페이지 설정"
|
||||||
nameAlreadyExists: "지정한 페이지 URL이 이미 존재합니다"
|
nameAlreadyExists: "지정한 페이지 URL이 이미 존재합니다"
|
||||||
invalidNameTitle: "유효하지 않은 페이지 URL입니다"
|
invalidNameTitle: "유효하지 않은 페이지 URL입니다"
|
||||||
|
|
|
@ -1459,9 +1459,6 @@ _pages:
|
||||||
newPage: "Utwórz stronę"
|
newPage: "Utwórz stronę"
|
||||||
editPage: "Edytuj tę stronę"
|
editPage: "Edytuj tę stronę"
|
||||||
readPage: "Aktywowano widok źródła"
|
readPage: "Aktywowano widok źródła"
|
||||||
created: "Pomyślnie utworzono stronę!"
|
|
||||||
updated: "Pomyślnie zaktualizowano stronę!"
|
|
||||||
deleted: "Strona została usunięta"
|
|
||||||
pageSetting: "Ustawienia strony"
|
pageSetting: "Ustawienia strony"
|
||||||
nameAlreadyExists: "Określony adres URL strony już istnieje"
|
nameAlreadyExists: "Określony adres URL strony już istnieje"
|
||||||
invalidNameTitle: "Podany adres URL strony jest nieprawidłowy"
|
invalidNameTitle: "Podany adres URL strony jest nieprawidłowy"
|
||||||
|
|
|
@ -2357,9 +2357,6 @@ _pages:
|
||||||
newPage: "Criar uma Página"
|
newPage: "Criar uma Página"
|
||||||
editPage: "Editar essa Página"
|
editPage: "Editar essa Página"
|
||||||
readPage: "Ver a fonte dessa Página"
|
readPage: "Ver a fonte dessa Página"
|
||||||
created: "Página criada com sucesso"
|
|
||||||
updated: "Página atualizada com sucesso"
|
|
||||||
deleted: "Página excluída com sucesso"
|
|
||||||
pageSetting: "Configurações da página"
|
pageSetting: "Configurações da página"
|
||||||
nameAlreadyExists: "O URL de Página especificado já existe"
|
nameAlreadyExists: "O URL de Página especificado já existe"
|
||||||
invalidNameTitle: "O URL de Página especificado é inválido"
|
invalidNameTitle: "O URL de Página especificado é inválido"
|
||||||
|
|
|
@ -1976,9 +1976,6 @@ _pages:
|
||||||
newPage: "Создать страницу"
|
newPage: "Создать страницу"
|
||||||
editPage: "Править страницу"
|
editPage: "Править страницу"
|
||||||
readPage: "Читать страницу"
|
readPage: "Читать страницу"
|
||||||
created: "Страница успешно создана."
|
|
||||||
updated: "Страница успешно обновлена."
|
|
||||||
deleted: "Страница успешно удалена."
|
|
||||||
pageSetting: "Настройки страницы"
|
pageSetting: "Настройки страницы"
|
||||||
nameAlreadyExists: "Указанный адрес страницы уже существует."
|
nameAlreadyExists: "Указанный адрес страницы уже существует."
|
||||||
invalidNameTitle: "Указанный адрес страницы недопустим."
|
invalidNameTitle: "Указанный адрес страницы недопустим."
|
||||||
|
|
|
@ -1332,9 +1332,6 @@ _pages:
|
||||||
newPage: "Vytvoriť novú stránku"
|
newPage: "Vytvoriť novú stránku"
|
||||||
editPage: "Upraviť túto stránku"
|
editPage: "Upraviť túto stránku"
|
||||||
readPage: "Zobrazenie zdroja aktívne"
|
readPage: "Zobrazenie zdroja aktívne"
|
||||||
created: "Stránka úspešne vytvorená"
|
|
||||||
updated: "Stránka úspešne upravená"
|
|
||||||
deleted: "Stránka úspešne odstránená"
|
|
||||||
pageSetting: "Nastavenia stránky"
|
pageSetting: "Nastavenia stránky"
|
||||||
nameAlreadyExists: "Zadaná URL stránku už existuje"
|
nameAlreadyExists: "Zadaná URL stránku už existuje"
|
||||||
invalidNameTitle: "Zadaná URL stránku je nesprávna"
|
invalidNameTitle: "Zadaná URL stránku je nesprávna"
|
||||||
|
|
|
@ -2331,9 +2331,6 @@ _pages:
|
||||||
newPage: "สร้างหน้าเพจใหม่"
|
newPage: "สร้างหน้าเพจใหม่"
|
||||||
editPage: "แก้ไขหน้าเพจ"
|
editPage: "แก้ไขหน้าเพจ"
|
||||||
readPage: "กำลังดูแหล่งที่มาของเพจนี้"
|
readPage: "กำลังดูแหล่งที่มาของเพจนี้"
|
||||||
created: "สร้างหน้าเพจสำเร็จเรียบร้อยแล้ว"
|
|
||||||
updated: "แก้ไขหน้าเพจสำเร็จเรียบร้อยแล้ว"
|
|
||||||
deleted: "ลบหน้าเพจสำเร็จเรียบร้อยแล้ว"
|
|
||||||
pageSetting: "การตั้งค่าหน้าเพจ"
|
pageSetting: "การตั้งค่าหน้าเพจ"
|
||||||
nameAlreadyExists: "URL ของหน้าที่ระบุนั้นมีอยู่แล้ว"
|
nameAlreadyExists: "URL ของหน้าที่ระบุนั้นมีอยู่แล้ว"
|
||||||
invalidNameTitle: "URL ของหน้าที่ระบุนั้นไม่ถูกต้อง"
|
invalidNameTitle: "URL ของหน้าที่ระบุนั้นไม่ถูกต้อง"
|
||||||
|
|
|
@ -1513,9 +1513,6 @@ _pages:
|
||||||
newPage: "Створити сторінку"
|
newPage: "Створити сторінку"
|
||||||
editPage: "Редагувати сторінку"
|
editPage: "Редагувати сторінку"
|
||||||
readPage: "Перегляд вихідного коду"
|
readPage: "Перегляд вихідного коду"
|
||||||
created: "Сторінка успішно створена."
|
|
||||||
updated: "Сторінка успішно оновлена."
|
|
||||||
deleted: "Сторінку видалено"
|
|
||||||
pageSetting: "Налаштування сторінки"
|
pageSetting: "Налаштування сторінки"
|
||||||
nameAlreadyExists: "Вказана адреса сторінки вже існує."
|
nameAlreadyExists: "Вказана адреса сторінки вже існує."
|
||||||
invalidNameTitle: "Вказана адреса сторінки неприпустима."
|
invalidNameTitle: "Вказана адреса сторінки неприпустима."
|
||||||
|
|
|
@ -1004,9 +1004,6 @@ _play:
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Yangi Sahifa yaratish"
|
newPage: "Yangi Sahifa yaratish"
|
||||||
editPage: "Ushbu Sahifani tahrirlash"
|
editPage: "Ushbu Sahifani tahrirlash"
|
||||||
created: "Sahifa muvaffaqiyatli yaratildi"
|
|
||||||
updated: "Sahifa muvaffaqiyatli tahrirlandi"
|
|
||||||
deleted: "Sahifa muvaffaqiyatli o'chirildi"
|
|
||||||
pageSetting: "Sahifa sozlamalari"
|
pageSetting: "Sahifa sozlamalari"
|
||||||
nameAlreadyExists: "Ko'rsatilgan Sahifa URL'i allaqachon mavjud"
|
nameAlreadyExists: "Ko'rsatilgan Sahifa URL'i allaqachon mavjud"
|
||||||
invalidNameTitle: "Ko'rsatilgan Sahifa URL'i yaroqsiz"
|
invalidNameTitle: "Ko'rsatilgan Sahifa URL'i yaroqsiz"
|
||||||
|
|
|
@ -1802,9 +1802,6 @@ _pages:
|
||||||
newPage: "Tạo Trang mới"
|
newPage: "Tạo Trang mới"
|
||||||
editPage: "Sửa Trang này"
|
editPage: "Sửa Trang này"
|
||||||
readPage: "Xem mã nguồn Trang này"
|
readPage: "Xem mã nguồn Trang này"
|
||||||
created: "Trang đã được tạo thành công"
|
|
||||||
updated: "Trang đã được cập nhật thành công"
|
|
||||||
deleted: "Trang đã được xóa thành công"
|
|
||||||
pageSetting: "Cài đặt trang"
|
pageSetting: "Cài đặt trang"
|
||||||
nameAlreadyExists: "URL Trang đã tồn tại"
|
nameAlreadyExists: "URL Trang đã tồn tại"
|
||||||
invalidNameTitle: "URL Trang không hợp lệ"
|
invalidNameTitle: "URL Trang không hợp lệ"
|
||||||
|
|
|
@ -2365,9 +2365,6 @@ _pages:
|
||||||
newPage: "创建页面"
|
newPage: "创建页面"
|
||||||
editPage: "编辑页面"
|
editPage: "编辑页面"
|
||||||
readPage: "查看页面"
|
readPage: "查看页面"
|
||||||
created: "页面已创建"
|
|
||||||
updated: "页面已更新"
|
|
||||||
deleted: "该页面已被删除"
|
|
||||||
pageSetting: "页面设置"
|
pageSetting: "页面设置"
|
||||||
nameAlreadyExists: "该页面 URL 已存在"
|
nameAlreadyExists: "该页面 URL 已存在"
|
||||||
invalidNameTitle: "无效的页面 URL"
|
invalidNameTitle: "无效的页面 URL"
|
||||||
|
|
|
@ -2365,9 +2365,6 @@ _pages:
|
||||||
newPage: "建立頁面"
|
newPage: "建立頁面"
|
||||||
editPage: "編輯頁面"
|
editPage: "編輯頁面"
|
||||||
readPage: "正在檢視原始碼"
|
readPage: "正在檢視原始碼"
|
||||||
created: "頁面已建立"
|
|
||||||
updated: "頁面已更新"
|
|
||||||
deleted: "頁面已被刪除"
|
|
||||||
pageSetting: "頁面設定"
|
pageSetting: "頁面設定"
|
||||||
nameAlreadyExists: "該頁面 URL 已存在"
|
nameAlreadyExists: "該頁面 URL 已存在"
|
||||||
invalidNameTitle: "無效的頁面 URL"
|
invalidNameTitle: "無效的頁面 URL"
|
||||||
|
|
38
package.json
38
package.json
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.2.0-beta.0",
|
"version": "2025.2.1-beta.0",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/misskey-dev/misskey.git"
|
"url": "https://github.com/misskey-dev/misskey.git"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@9.6.0",
|
"packageManager": "pnpm@9.15.4",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/frontend-shared",
|
"packages/frontend-shared",
|
||||||
"packages/frontend",
|
"packages/frontend",
|
||||||
|
@ -47,35 +47,35 @@
|
||||||
"cleanall": "pnpm clean-all"
|
"cleanall": "pnpm clean-all"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"chokidar": "3.5.3",
|
"chokidar": "3.6.0",
|
||||||
"lodash": "4.17.21"
|
"lodash": "4.17.21"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssnano": "6.1.2",
|
"cssnano": "7.0.6",
|
||||||
"execa": "8.0.1",
|
"execa": "8.0.1",
|
||||||
"fast-glob": "3.3.2",
|
"fast-glob": "3.3.3",
|
||||||
"ignore-walk": "6.0.5",
|
"ignore-walk": "6.0.5",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"postcss": "8.4.49",
|
"postcss": "8.5.2",
|
||||||
"tar": "6.2.1",
|
"tar": "6.2.1",
|
||||||
"terser": "5.36.0",
|
"terser": "5.39.0",
|
||||||
"typescript": "5.6.3",
|
"typescript": "5.7.3",
|
||||||
"esbuild": "0.24.0",
|
"esbuild": "0.25.0",
|
||||||
"glob": "11.0.0"
|
"glob": "11.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@misskey-dev/eslint-plugin": "2.0.3",
|
"@misskey-dev/eslint-plugin": "2.1.0",
|
||||||
"@types/node": "22.9.0",
|
"@types/node": "22.13.4",
|
||||||
"@typescript-eslint/eslint-plugin": "7.17.0",
|
"@typescript-eslint/eslint-plugin": "8.24.0",
|
||||||
"@typescript-eslint/parser": "7.17.0",
|
"@typescript-eslint/parser": "8.24.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "13.15.2",
|
"cypress": "14.0.3",
|
||||||
"eslint": "9.14.0",
|
"eslint": "9.20.1",
|
||||||
"globals": "15.12.0",
|
"globals": "15.15.0",
|
||||||
"ncp": "2.0.0",
|
"ncp": "2.0.0",
|
||||||
"start-server-and-test": "2.0.8"
|
"start-server-and-test": "2.0.10"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@tensorflow/tfjs-core": "4.4.0"
|
"@tensorflow/tfjs-core": "4.22.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/swcrc",
|
"$schema": "https://swc.rs/schema.json",
|
||||||
"jsc": {
|
"jsc": {
|
||||||
"parser": {
|
"parser": {
|
||||||
"syntax": "typescript",
|
"syntax": "typescript",
|
||||||
|
|
|
@ -37,20 +37,20 @@
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@swc/core-android-arm64": "1.3.11",
|
"@swc/core-android-arm64": "1.3.11",
|
||||||
"@swc/core-darwin-arm64": "1.3.56",
|
"@swc/core-darwin-arm64": "1.10.16",
|
||||||
"@swc/core-darwin-x64": "1.3.56",
|
"@swc/core-darwin-x64": "1.10.16",
|
||||||
"@swc/core-freebsd-x64": "1.3.11",
|
"@swc/core-freebsd-x64": "1.3.11",
|
||||||
"@swc/core-linux-arm-gnueabihf": "1.3.56",
|
"@swc/core-linux-arm-gnueabihf": "1.10.16",
|
||||||
"@swc/core-linux-arm64-gnu": "1.3.56",
|
"@swc/core-linux-arm64-gnu": "1.10.16",
|
||||||
"@swc/core-linux-arm64-musl": "1.3.56",
|
"@swc/core-linux-arm64-musl": "1.10.16",
|
||||||
"@swc/core-linux-x64-gnu": "1.3.56",
|
"@swc/core-linux-x64-gnu": "1.10.16",
|
||||||
"@swc/core-linux-x64-musl": "1.3.56",
|
"@swc/core-linux-x64-musl": "1.10.16",
|
||||||
"@swc/core-win32-arm64-msvc": "1.3.56",
|
"@swc/core-win32-arm64-msvc": "1.10.16",
|
||||||
"@swc/core-win32-ia32-msvc": "1.3.56",
|
"@swc/core-win32-ia32-msvc": "1.10.16",
|
||||||
"@swc/core-win32-x64-msvc": "1.3.56",
|
"@swc/core-win32-x64-msvc": "1.10.16",
|
||||||
"@tensorflow/tfjs": "4.4.0",
|
"@tensorflow/tfjs": "4.22.0",
|
||||||
"@tensorflow/tfjs-node": "4.4.0",
|
"@tensorflow/tfjs-node": "4.22.0",
|
||||||
"bufferutil": "4.0.7",
|
"bufferutil": "4.0.9",
|
||||||
"slacc-android-arm-eabi": "0.0.10",
|
"slacc-android-arm-eabi": "0.0.10",
|
||||||
"slacc-android-arm64": "0.0.10",
|
"slacc-android-arm64": "0.0.10",
|
||||||
"slacc-darwin-arm64": "0.0.10",
|
"slacc-darwin-arm64": "0.0.10",
|
||||||
|
@ -64,37 +64,37 @@
|
||||||
"slacc-linux-x64-musl": "0.0.10",
|
"slacc-linux-x64-musl": "0.0.10",
|
||||||
"slacc-win32-arm64-msvc": "0.0.10",
|
"slacc-win32-arm64-msvc": "0.0.10",
|
||||||
"slacc-win32-x64-msvc": "0.0.10",
|
"slacc-win32-x64-msvc": "0.0.10",
|
||||||
"utf-8-validate": "6.0.3"
|
"utf-8-validate": "6.0.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.620.0",
|
"@aws-sdk/client-s3": "3.749.0",
|
||||||
"@aws-sdk/lib-storage": "3.620.0",
|
"@aws-sdk/lib-storage": "3.749.0",
|
||||||
"@bull-board/api": "6.5.0",
|
"@bull-board/api": "6.7.7",
|
||||||
"@bull-board/fastify": "6.5.0",
|
"@bull-board/fastify": "6.7.7",
|
||||||
"@bull-board/ui": "6.5.0",
|
"@bull-board/ui": "6.7.7",
|
||||||
"@discordapp/twemoji": "15.1.0",
|
"@discordapp/twemoji": "15.1.0",
|
||||||
"@fastify/accepts": "5.0.1",
|
"@fastify/accepts": "5.0.2",
|
||||||
"@fastify/cookie": "11.0.1",
|
"@fastify/cookie": "11.0.2",
|
||||||
"@fastify/cors": "10.0.1",
|
"@fastify/cors": "10.0.2",
|
||||||
"@fastify/express": "4.0.1",
|
"@fastify/express": "4.0.2",
|
||||||
"@fastify/http-proxy": "10.0.1",
|
"@fastify/http-proxy": "10.0.2",
|
||||||
"@fastify/multipart": "9.0.1",
|
"@fastify/multipart": "9.0.3",
|
||||||
"@fastify/static": "8.0.2",
|
"@fastify/static": "8.1.0",
|
||||||
"@fastify/view": "10.0.1",
|
"@fastify/view": "10.0.2",
|
||||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||||
"@misskey-dev/summaly": "5.1.0",
|
"@misskey-dev/summaly": "5.2.0",
|
||||||
"@napi-rs/canvas": "0.1.56",
|
"@napi-rs/canvas": "0.1.67",
|
||||||
"@nestjs/common": "10.4.7",
|
"@nestjs/common": "11.0.9",
|
||||||
"@nestjs/core": "10.4.7",
|
"@nestjs/core": "11.0.9",
|
||||||
"@nestjs/testing": "10.4.7",
|
"@nestjs/testing": "11.0.9",
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@sentry/node": "8.38.0",
|
"@sentry/node": "8.55.0",
|
||||||
"@sentry/profiling-node": "8.38.0",
|
"@sentry/profiling-node": "8.55.0",
|
||||||
"@simplewebauthn/server": "10.0.1",
|
"@simplewebauthn/server": "12.0.0",
|
||||||
"@sinonjs/fake-timers": "11.2.2",
|
"@sinonjs/fake-timers": "11.3.1",
|
||||||
"@smithy/node-http-handler": "2.5.0",
|
"@smithy/node-http-handler": "2.5.0",
|
||||||
"@swc/cli": "0.3.12",
|
"@swc/cli": "0.6.0",
|
||||||
"@swc/core": "1.9.2",
|
"@swc/core": "1.10.16",
|
||||||
"@twemoji/parser": "15.1.1",
|
"@twemoji/parser": "15.1.1",
|
||||||
"accepts": "1.3.8",
|
"accepts": "1.3.8",
|
||||||
"ajv": "8.17.1",
|
"ajv": "8.17.1",
|
||||||
|
@ -103,10 +103,10 @@
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"body-parser": "1.20.3",
|
"body-parser": "1.20.3",
|
||||||
"bullmq": "5.26.1",
|
"bullmq": "5.41.1",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "7.0.0",
|
||||||
"cbor": "9.0.2",
|
"cbor": "9.0.2",
|
||||||
"chalk": "5.3.0",
|
"chalk": "5.4.1",
|
||||||
"chalk-template": "1.1.0",
|
"chalk-template": "1.1.0",
|
||||||
"chokidar": "3.6.0",
|
"chokidar": "3.6.0",
|
||||||
"cli-highlight": "2.1.11",
|
"cli-highlight": "2.1.11",
|
||||||
|
@ -114,46 +114,46 @@
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "0.5.4",
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "2.30.0",
|
||||||
"deep-email-validator": "0.1.21",
|
"deep-email-validator": "0.1.21",
|
||||||
"fastify": "5.0.0",
|
"fastify": "5.2.1",
|
||||||
"fastify-raw-body": "5.0.0",
|
"fastify-raw-body": "5.0.0",
|
||||||
"feed": "4.2.2",
|
"feed": "4.2.2",
|
||||||
"file-type": "19.6.0",
|
"file-type": "19.6.0",
|
||||||
"fluent-ffmpeg": "2.1.3",
|
"fluent-ffmpeg": "2.1.3",
|
||||||
"form-data": "4.0.1",
|
"form-data": "4.0.2",
|
||||||
"got": "14.4.4",
|
"got": "14.4.6",
|
||||||
"happy-dom": "15.11.4",
|
"happy-dom": "16.8.1",
|
||||||
"hpagent": "1.2.0",
|
"hpagent": "1.2.0",
|
||||||
"htmlescape": "1.1.1",
|
"htmlescape": "1.1.1",
|
||||||
"http-link-header": "1.1.3",
|
"http-link-header": "1.1.3",
|
||||||
"ioredis": "5.4.1",
|
"ioredis": "5.5.0",
|
||||||
"ip-cidr": "4.0.2",
|
"ip-cidr": "4.0.2",
|
||||||
"ipaddr.js": "2.2.0",
|
"ipaddr.js": "2.2.0",
|
||||||
"is-svg": "5.1.0",
|
"is-svg": "5.1.0",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"jsdom": "24.1.1",
|
"jsdom": "26.0.0",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"jsonld": "8.3.2",
|
"jsonld": "8.3.3",
|
||||||
"jsrsasign": "11.1.0",
|
"jsrsasign": "11.1.0",
|
||||||
"juice": "11.0.0",
|
"juice": "11.0.0",
|
||||||
"meilisearch": "0.45.0",
|
"meilisearch": "0.48.2",
|
||||||
"mfm-js": "0.24.0",
|
"mfm-js": "0.24.0",
|
||||||
"microformats-parser": "2.0.2",
|
"microformats-parser": "2.0.2",
|
||||||
"mime-types": "2.1.35",
|
"mime-types": "2.1.35",
|
||||||
"misskey-js": "workspace:*",
|
"misskey-js": "workspace:*",
|
||||||
"misskey-reversi": "workspace:*",
|
"misskey-reversi": "workspace:*",
|
||||||
"ms": "3.0.0-canary.1",
|
"ms": "3.0.0-canary.1",
|
||||||
"nanoid": "5.0.8",
|
"nanoid": "5.1.0",
|
||||||
"nested-property": "4.0.0",
|
"nested-property": "4.0.0",
|
||||||
"node-fetch": "3.3.2",
|
"node-fetch": "3.3.2",
|
||||||
"nodemailer": "6.9.16",
|
"nodemailer": "6.10.0",
|
||||||
"nsfwjs": "4.2.0",
|
"nsfwjs": "4.2.0",
|
||||||
"oauth": "0.10.0",
|
"oauth": "0.10.0",
|
||||||
"oauth2orize": "1.12.0",
|
"oauth2orize": "1.12.0",
|
||||||
"oauth2orize-pkce": "0.1.2",
|
"oauth2orize-pkce": "0.1.2",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"otpauth": "9.3.4",
|
"otpauth": "9.3.6",
|
||||||
"parse5": "7.2.1",
|
"parse5": "7.2.1",
|
||||||
"pg": "8.13.1",
|
"pg": "8.13.3",
|
||||||
"pkce-challenge": "4.1.0",
|
"pkce-challenge": "4.1.0",
|
||||||
"probe-image-size": "7.2.3",
|
"probe-image-size": "7.2.3",
|
||||||
"promise-limit": "2.7.0",
|
"promise-limit": "2.7.0",
|
||||||
|
@ -167,19 +167,19 @@
|
||||||
"rename": "1.0.4",
|
"rename": "1.0.4",
|
||||||
"rss-parser": "3.13.0",
|
"rss-parser": "3.13.0",
|
||||||
"rxjs": "7.8.1",
|
"rxjs": "7.8.1",
|
||||||
"sanitize-html": "2.13.1",
|
"sanitize-html": "2.14.0",
|
||||||
"secure-json-parse": "2.7.0",
|
"secure-json-parse": "3.0.2",
|
||||||
"sharp": "0.33.5",
|
"sharp": "0.33.5",
|
||||||
"slacc": "0.0.10",
|
"slacc": "0.0.10",
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"systeminformation": "5.23.5",
|
"systeminformation": "5.25.11",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tmp": "0.2.3",
|
"tmp": "0.2.3",
|
||||||
"tsc-alias": "1.8.10",
|
"tsc-alias": "1.8.10",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"typeorm": "0.3.20",
|
"typeorm": "0.3.20",
|
||||||
"typescript": "5.6.3",
|
"typescript": "5.7.3",
|
||||||
"ulid": "2.3.0",
|
"ulid": "2.3.0",
|
||||||
"vary": "1.1.2",
|
"vary": "1.1.2",
|
||||||
"web-push": "3.6.7",
|
"web-push": "3.6.7",
|
||||||
|
@ -188,8 +188,8 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/globals": "29.7.0",
|
"@jest/globals": "29.7.0",
|
||||||
"@nestjs/platform-express": "10.4.7",
|
"@nestjs/platform-express": "10.4.15",
|
||||||
"@simplewebauthn/types": "10.0.0",
|
"@simplewebauthn/types": "12.0.0",
|
||||||
"@swc/jest": "0.2.37",
|
"@swc/jest": "0.2.37",
|
||||||
"@types/accepts": "1.3.7",
|
"@types/accepts": "1.3.7",
|
||||||
"@types/archiver": "6.0.3",
|
"@types/archiver": "6.0.3",
|
||||||
|
@ -204,15 +204,15 @@
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "4.0.9",
|
||||||
"@types/jsdom": "21.1.7",
|
"@types/jsdom": "21.1.7",
|
||||||
"@types/jsonld": "1.5.15",
|
"@types/jsonld": "1.5.15",
|
||||||
"@types/jsrsasign": "10.5.14",
|
"@types/jsrsasign": "10.5.15",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/ms": "0.7.34",
|
"@types/ms": "0.7.34",
|
||||||
"@types/node": "22.9.0",
|
"@types/node": "22.13.4",
|
||||||
"@types/nodemailer": "6.4.16",
|
"@types/nodemailer": "6.4.17",
|
||||||
"@types/oauth": "0.9.6",
|
"@types/oauth": "0.9.6",
|
||||||
"@types/oauth2orize": "1.11.5",
|
"@types/oauth2orize": "1.11.5",
|
||||||
"@types/oauth2orize-pkce": "0.1.2",
|
"@types/oauth2orize-pkce": "0.1.2",
|
||||||
"@types/pg": "8.11.10",
|
"@types/pg": "8.11.11",
|
||||||
"@types/pug": "2.0.10",
|
"@types/pug": "2.0.10",
|
||||||
"@types/qrcode": "1.5.5",
|
"@types/qrcode": "1.5.5",
|
||||||
"@types/random-seed": "0.3.5",
|
"@types/random-seed": "0.3.5",
|
||||||
|
@ -226,18 +226,18 @@
|
||||||
"@types/tmp": "0.2.6",
|
"@types/tmp": "0.2.6",
|
||||||
"@types/vary": "1.1.3",
|
"@types/vary": "1.1.3",
|
||||||
"@types/web-push": "3.6.4",
|
"@types/web-push": "3.6.4",
|
||||||
"@types/ws": "8.5.13",
|
"@types/ws": "8.5.14",
|
||||||
"@typescript-eslint/eslint-plugin": "7.17.0",
|
"@typescript-eslint/eslint-plugin": "8.24.0",
|
||||||
"@typescript-eslint/parser": "7.17.0",
|
"@typescript-eslint/parser": "8.24.0",
|
||||||
"aws-sdk-client-mock": "4.0.1",
|
"aws-sdk-client-mock": "4.1.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint-plugin-import": "2.30.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
"execa": "8.0.1",
|
"execa": "8.0.1",
|
||||||
"fkill": "9.0.0",
|
"fkill": "9.0.0",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-mock": "29.7.0",
|
"jest-mock": "29.7.0",
|
||||||
"nodemon": "3.1.7",
|
"nodemon": "3.1.9",
|
||||||
"pid-port": "1.0.0",
|
"pid-port": "1.0.2",
|
||||||
"simple-oauth2": "5.1.0"
|
"simple-oauth2": "5.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ type Source = {
|
||||||
proxyBypassHosts?: string[];
|
proxyBypassHosts?: string[];
|
||||||
|
|
||||||
allowedPrivateNetworks?: string[];
|
allowedPrivateNetworks?: string[];
|
||||||
|
disallowExternalApRedirect?: boolean;
|
||||||
|
|
||||||
maxFileSize?: number;
|
maxFileSize?: number;
|
||||||
|
|
||||||
|
@ -105,8 +106,8 @@ type Source = {
|
||||||
|
|
||||||
logging?: {
|
logging?: {
|
||||||
sql?: {
|
sql?: {
|
||||||
disableQueryTruncation? : boolean,
|
disableQueryTruncation?: boolean,
|
||||||
enableQueryParamLogging? : boolean,
|
enableQueryParamLogging?: boolean,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -149,6 +150,7 @@ export type Config = {
|
||||||
proxySmtp: string | undefined;
|
proxySmtp: string | undefined;
|
||||||
proxyBypassHosts: string[] | undefined;
|
proxyBypassHosts: string[] | undefined;
|
||||||
allowedPrivateNetworks: string[] | undefined;
|
allowedPrivateNetworks: string[] | undefined;
|
||||||
|
disallowExternalApRedirect: boolean;
|
||||||
maxFileSize: number;
|
maxFileSize: number;
|
||||||
clusterLimit: number | undefined;
|
clusterLimit: number | undefined;
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -166,8 +168,8 @@ export type Config = {
|
||||||
signToActivityPubGet: boolean | undefined;
|
signToActivityPubGet: boolean | undefined;
|
||||||
logging?: {
|
logging?: {
|
||||||
sql?: {
|
sql?: {
|
||||||
disableQueryTruncation? : boolean,
|
disableQueryTruncation?: boolean,
|
||||||
enableQueryParamLogging? : boolean,
|
enableQueryParamLogging?: boolean,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,6 +289,7 @@ export function loadConfig(): Config {
|
||||||
proxySmtp: config.proxySmtp,
|
proxySmtp: config.proxySmtp,
|
||||||
proxyBypassHosts: config.proxyBypassHosts,
|
proxyBypassHosts: config.proxyBypassHosts,
|
||||||
allowedPrivateNetworks: config.allowedPrivateNetworks,
|
allowedPrivateNetworks: config.allowedPrivateNetworks,
|
||||||
|
disallowExternalApRedirect: config.disallowExternalApRedirect ?? false,
|
||||||
maxFileSize: config.maxFileSize ?? 262144000,
|
maxFileSize: config.maxFileSize ?? 262144000,
|
||||||
clusterLimit: config.clusterLimit,
|
clusterLimit: config.clusterLimit,
|
||||||
outgoingAddress: config.outgoingAddress,
|
outgoingAddress: config.outgoingAddress,
|
||||||
|
|
|
@ -43,7 +43,7 @@ export type CaptchaSetting = {
|
||||||
siteKey: string | null;
|
siteKey: string | null;
|
||||||
secretKey: string | null;
|
secretKey: string | null;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export class CaptchaError extends Error {
|
export class CaptchaError extends Error {
|
||||||
public readonly code: CaptchaErrorCode;
|
public readonly code: CaptchaErrorCode;
|
||||||
|
@ -59,11 +59,11 @@ export class CaptchaError extends Error {
|
||||||
|
|
||||||
export type CaptchaSaveSuccess = {
|
export type CaptchaSaveSuccess = {
|
||||||
success: true;
|
success: true;
|
||||||
}
|
};
|
||||||
export type CaptchaSaveFailure = {
|
export type CaptchaSaveFailure = {
|
||||||
success: false;
|
success: false;
|
||||||
error: CaptchaError;
|
error: CaptchaError;
|
||||||
}
|
};
|
||||||
export type CaptchaSaveResult = CaptchaSaveSuccess | CaptchaSaveFailure;
|
export type CaptchaSaveResult = CaptchaSaveSuccess | CaptchaSaveFailure;
|
||||||
|
|
||||||
type CaptchaResponse = {
|
type CaptchaResponse = {
|
||||||
|
|
|
@ -173,7 +173,8 @@ export class DriveService {
|
||||||
?? `${ this.meta.objectStorageUseSSL ? 'https' : 'http' }://${ this.meta.objectStorageEndpoint }${ this.meta.objectStoragePort ? `:${this.meta.objectStoragePort}` : '' }/${ this.meta.objectStorageBucket }`;
|
?? `${ this.meta.objectStorageUseSSL ? 'https' : 'http' }://${ this.meta.objectStorageEndpoint }${ this.meta.objectStoragePort ? `:${this.meta.objectStoragePort}` : '' }/${ this.meta.objectStorageBucket }`;
|
||||||
|
|
||||||
// for original
|
// for original
|
||||||
const key = `${this.meta.objectStoragePrefix}/${randomUUID()}${ext}`;
|
const prefix = this.meta.objectStoragePrefix ? `${this.meta.objectStoragePrefix}/` : '';
|
||||||
|
const key = `${prefix}${randomUUID()}${ext}`;
|
||||||
const url = `${ baseUrl }/${ key }`;
|
const url = `${ baseUrl }/${ key }`;
|
||||||
|
|
||||||
// for alts
|
// for alts
|
||||||
|
@ -190,7 +191,7 @@ export class DriveService {
|
||||||
];
|
];
|
||||||
|
|
||||||
if (alts.webpublic) {
|
if (alts.webpublic) {
|
||||||
webpublicKey = `${this.meta.objectStoragePrefix}/webpublic-${randomUUID()}.${alts.webpublic.ext}`;
|
webpublicKey = `${prefix}webpublic-${randomUUID()}.${alts.webpublic.ext}`;
|
||||||
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
|
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
|
||||||
|
|
||||||
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
|
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
|
||||||
|
@ -198,7 +199,7 @@ export class DriveService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alts.thumbnail) {
|
if (alts.thumbnail) {
|
||||||
thumbnailKey = `${this.meta.objectStoragePrefix}/thumbnail-${randomUUID()}.${alts.thumbnail.ext}`;
|
thumbnailKey = `${prefix}thumbnail-${randomUUID()}.${alts.thumbnail.ext}`;
|
||||||
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
|
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
|
||||||
|
|
||||||
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
|
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
|
||||||
|
|
|
@ -164,6 +164,13 @@ export class EmailService {
|
||||||
available: boolean;
|
available: boolean;
|
||||||
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist';
|
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist';
|
||||||
}> {
|
}> {
|
||||||
|
if (!this.utilityService.validateEmailFormat(emailAddress)) {
|
||||||
|
return {
|
||||||
|
available: false,
|
||||||
|
reason: 'format',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const exist = await this.userProfilesRepository.countBy({
|
const exist = await this.userProfilesRepository.countBy({
|
||||||
emailVerified: true,
|
emailVerified: true,
|
||||||
email: emailAddress,
|
email: emailAddress,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
|
||||||
export type FanoutTimelineName =
|
export type FanoutTimelineName = (
|
||||||
// home timeline
|
// home timeline
|
||||||
| `homeTimeline:${string}`
|
| `homeTimeline:${string}`
|
||||||
| `homeTimelineWithFiles:${string}` // only notes with files are included
|
| `homeTimelineWithFiles:${string}` // only notes with files are included
|
||||||
|
@ -37,6 +37,7 @@ export type FanoutTimelineName =
|
||||||
|
|
||||||
// role timelines
|
// role timelines
|
||||||
| `roleTimeline:${string}` // any notes are included
|
| `roleTimeline:${string}` // any notes are included
|
||||||
|
);
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FanoutTimelineService {
|
export class FanoutTimelineService {
|
||||||
|
|
|
@ -211,7 +211,7 @@ type SerializedAll<T> = {
|
||||||
|
|
||||||
type UndefinedAsNullAll<T> = {
|
type UndefinedAsNullAll<T> = {
|
||||||
[K in keyof T]: T[K] extends undefined ? null : T[K];
|
[K in keyof T]: T[K] extends undefined ? null : T[K];
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface InternalEventTypes {
|
export interface InternalEventTypes {
|
||||||
userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; };
|
userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; };
|
||||||
|
|
|
@ -16,7 +16,7 @@ import type { Config } from '@/config.js';
|
||||||
import { StatusError } from '@/misc/status-error.js';
|
import { StatusError } from '@/misc/status-error.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
||||||
import { assertActivityMatchesUrls } from '@/core/activitypub/misc/check-against-url.js';
|
import { assertActivityMatchesUrls, FetchAllowSoftFailMask } from '@/core/activitypub/misc/check-against-url.js';
|
||||||
import type { IObject } from '@/core/activitypub/type.js';
|
import type { IObject } from '@/core/activitypub/type.js';
|
||||||
import type { Response } from 'node-fetch';
|
import type { Response } from 'node-fetch';
|
||||||
import type { URL } from 'node:url';
|
import type { URL } from 'node:url';
|
||||||
|
@ -215,7 +215,7 @@ export class HttpRequestService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async getActivityJson(url: string, isLocalAddressAllowed = false): Promise<IObject> {
|
public async getActivityJson(url: string, isLocalAddressAllowed = false, allowSoftfail: FetchAllowSoftFailMask = FetchAllowSoftFailMask.Strict): Promise<IObject> {
|
||||||
const res = await this.send(url, {
|
const res = await this.send(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -232,7 +232,7 @@ export class HttpRequestService {
|
||||||
const finalUrl = res.url; // redirects may have been involved
|
const finalUrl = res.url; // redirects may have been involved
|
||||||
const activity = await res.json() as IObject;
|
const activity = await res.json() as IObject;
|
||||||
|
|
||||||
assertActivityMatchesUrls(activity, [finalUrl]);
|
assertActivityMatchesUrls(url, activity, [finalUrl], allowSoftfail);
|
||||||
|
|
||||||
return activity;
|
return activity;
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,7 +492,8 @@ export class MfmService {
|
||||||
|
|
||||||
appendChildren(nodes, body);
|
appendChildren(nodes, body);
|
||||||
|
|
||||||
const serialized = new XMLSerializer().serializeToString(body);
|
// Remove the unnecessary namespace
|
||||||
|
const serialized = new XMLSerializer().serializeToString(body).replace(/^\s*<p xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">/, '<p>');
|
||||||
|
|
||||||
happyDOM.close().catch(err => {});
|
happyDOM.close().catch(err => {});
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,7 @@ export class SearchService {
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
.leftJoinAndSelect('renote.user', 'renoteUser');
|
||||||
|
|
||||||
if (this.config.fulltextSearch?.provider === 'sqlPgroonga') {
|
if (this.config.fulltextSearch?.provider === 'sqlPgroonga') {
|
||||||
query.andWhere('note.text &@ :q', { q });
|
query.andWhere('note.text &@~ :q', { q });
|
||||||
} else {
|
} else {
|
||||||
query.andWhere('LOWER(note.text) LIKE :q', { q: `%${ sqlLikeEscape(q.toLowerCase()) }%` });
|
query.andWhere('LOWER(note.text) LIKE :q', { q: `%${ sqlLikeEscape(q.toLowerCase()) }%` });
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
export type UserWebhookPayload<T extends WebhookEventTypes> =
|
export type UserWebhookPayload<T extends WebhookEventTypes> =
|
||||||
T extends 'note' | 'reply' | 'renote' |'mention' ? {
|
T extends 'note' | 'reply' | 'renote' | 'mention' ? {
|
||||||
note: Packed<'Note'>,
|
note: Packed<'Note'>,
|
||||||
} :
|
} :
|
||||||
T extends 'follow' | 'unfollow' ? {
|
T extends 'follow' | 'unfollow' ? {
|
||||||
|
|
|
@ -38,6 +38,14 @@ export class UtilityService {
|
||||||
return this.punyHost(uri) === this.toPuny(this.config.host);
|
return this.punyHost(uri) === this.toPuny(this.config.host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// メールアドレスのバリデーションを行う
|
||||||
|
// https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
||||||
|
@bindThis
|
||||||
|
public validateEmailFormat(email: string): boolean {
|
||||||
|
const regexp = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
||||||
|
return regexp.test(email);
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public isBlockedHost(blockedHosts: string[], host: string | null): boolean {
|
public isBlockedHost(blockedHosts: string[], host: string | null): boolean {
|
||||||
if (host == null) return false;
|
if (host == null) return false;
|
||||||
|
|
|
@ -127,11 +127,11 @@ export class WebAuthnService {
|
||||||
const { registrationInfo } = verification;
|
const { registrationInfo } = verification;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
credentialID: registrationInfo.credentialID,
|
credentialID: registrationInfo.credential.id,
|
||||||
credentialPublicKey: registrationInfo.credentialPublicKey,
|
credentialPublicKey: registrationInfo.credential.publicKey,
|
||||||
attestationObject: registrationInfo.attestationObject,
|
attestationObject: registrationInfo.attestationObject,
|
||||||
fmt: registrationInfo.fmt,
|
fmt: registrationInfo.fmt,
|
||||||
counter: registrationInfo.counter,
|
counter: registrationInfo.credential.counter,
|
||||||
userVerified: registrationInfo.userVerified,
|
userVerified: registrationInfo.userVerified,
|
||||||
credentialDeviceType: registrationInfo.credentialDeviceType,
|
credentialDeviceType: registrationInfo.credentialDeviceType,
|
||||||
credentialBackedUp: registrationInfo.credentialBackedUp,
|
credentialBackedUp: registrationInfo.credentialBackedUp,
|
||||||
|
@ -212,9 +212,9 @@ export class WebAuthnService {
|
||||||
expectedChallenge: challenge,
|
expectedChallenge: challenge,
|
||||||
expectedOrigin: relyingParty.origin,
|
expectedOrigin: relyingParty.origin,
|
||||||
expectedRPID: relyingParty.rpId,
|
expectedRPID: relyingParty.rpId,
|
||||||
authenticator: {
|
credential: {
|
||||||
credentialID: key.id,
|
id: key.id,
|
||||||
credentialPublicKey: Buffer.from(key.publicKey, 'base64url'),
|
publicKey: Buffer.from(key.publicKey, 'base64url'),
|
||||||
counter: key.counter,
|
counter: key.counter,
|
||||||
transports: key.transports ? key.transports as AuthenticatorTransportFuture[] : undefined,
|
transports: key.transports ? key.transports as AuthenticatorTransportFuture[] : undefined,
|
||||||
},
|
},
|
||||||
|
@ -292,9 +292,9 @@ export class WebAuthnService {
|
||||||
expectedChallenge: challenge,
|
expectedChallenge: challenge,
|
||||||
expectedOrigin: relyingParty.origin,
|
expectedOrigin: relyingParty.origin,
|
||||||
expectedRPID: relyingParty.rpId,
|
expectedRPID: relyingParty.rpId,
|
||||||
authenticator: {
|
credential: {
|
||||||
credentialID: key.id,
|
id: key.id,
|
||||||
credentialPublicKey: Buffer.from(key.publicKey, 'base64url'),
|
publicKey: Buffer.from(key.publicKey, 'base64url'),
|
||||||
counter: key.counter,
|
counter: key.counter,
|
||||||
transports: key.transports ? key.transports as AuthenticatorTransportFuture[] : undefined,
|
transports: key.transports ? key.transports as AuthenticatorTransportFuture[] : undefined,
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
||||||
import { assertActivityMatchesUrls } from '@/core/activitypub/misc/check-against-url.js';
|
import { assertActivityMatchesUrls, FetchAllowSoftFailMask as FetchAllowSoftFailMask } from '@/core/activitypub/misc/check-against-url.js';
|
||||||
import type { IObject } from './type.js';
|
import type { IObject } from './type.js';
|
||||||
|
|
||||||
type Request = {
|
type Request = {
|
||||||
|
@ -185,7 +185,7 @@ export class ApRequestService {
|
||||||
* @param url URL to fetch
|
* @param url URL to fetch
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async signedGet(url: string, user: { id: MiUser['id'] }, followAlternate?: boolean): Promise<unknown> {
|
public async signedGet(url: string, user: { id: MiUser['id'] }, allowSoftfail: FetchAllowSoftFailMask = FetchAllowSoftFailMask.Strict, followAlternate?: boolean): Promise<unknown> {
|
||||||
const _followAlternate = followAlternate ?? true;
|
const _followAlternate = followAlternate ?? true;
|
||||||
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ export class ApRequestService {
|
||||||
if (alternate) {
|
if (alternate) {
|
||||||
const href = alternate.getAttribute('href');
|
const href = alternate.getAttribute('href');
|
||||||
if (href && this.utilityService.punyHost(url) === this.utilityService.punyHost(href)) {
|
if (href && this.utilityService.punyHost(url) === this.utilityService.punyHost(href)) {
|
||||||
return await this.signedGet(href, user, false);
|
return await this.signedGet(href, user, allowSoftfail, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -258,7 +258,7 @@ export class ApRequestService {
|
||||||
const finalUrl = res.url; // redirects may have been involved
|
const finalUrl = res.url; // redirects may have been involved
|
||||||
const activity = await res.json() as IObject;
|
const activity = await res.json() as IObject;
|
||||||
|
|
||||||
assertActivityMatchesUrls(activity, [finalUrl]);
|
assertActivityMatchesUrls(url, activity, [finalUrl], allowSoftfail);
|
||||||
|
|
||||||
return activity;
|
return activity;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { ApRendererService } from './ApRendererService.js';
|
||||||
import { ApRequestService } from './ApRequestService.js';
|
import { ApRequestService } from './ApRequestService.js';
|
||||||
import type { IObject, ICollection, IOrderedCollection } from './type.js';
|
import type { IObject, ICollection, IOrderedCollection } from './type.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
|
import { FetchAllowSoftFailMask } from './misc/check-against-url.js';
|
||||||
|
|
||||||
export class Resolver {
|
export class Resolver {
|
||||||
private history: Set<string>;
|
private history: Set<string>;
|
||||||
|
@ -72,7 +73,7 @@ export class Resolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async resolve(value: string | IObject): Promise<IObject> {
|
public async resolve(value: string | IObject, allowSoftfail: FetchAllowSoftFailMask = FetchAllowSoftFailMask.Strict): Promise<IObject> {
|
||||||
if (typeof value !== 'string') {
|
if (typeof value !== 'string') {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -108,8 +109,8 @@ export class Resolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
const object = (this.user
|
const object = (this.user
|
||||||
? await this.apRequestService.signedGet(value, this.user) as IObject
|
? await this.apRequestService.signedGet(value, this.user, allowSoftfail) as IObject
|
||||||
: await this.httpRequestService.getActivityJson(value)) as IObject;
|
: await this.httpRequestService.getActivityJson(value, undefined, allowSoftfail)) as IObject;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
Array.isArray(object['@context']) ?
|
Array.isArray(object['@context']) ?
|
||||||
|
@ -118,19 +119,7 @@ export class Resolver {
|
||||||
) {
|
) {
|
||||||
throw new IdentifiableError('72180409-793c-4973-868e-5a118eb5519b', 'invalid response');
|
throw new IdentifiableError('72180409-793c-4973-868e-5a118eb5519b', 'invalid response');
|
||||||
}
|
}
|
||||||
|
|
||||||
// HttpRequestService / ApRequestService have already checked that
|
|
||||||
// `object.id` or `object.url` matches the URL used to fetch the
|
|
||||||
// object after redirects; here we double-check that no redirects
|
|
||||||
// bounced between hosts
|
|
||||||
if (object.id == null) {
|
|
||||||
throw new IdentifiableError('ad2dc287-75c1-44c4-839d-3d2e64576675', 'invalid AP object: missing id');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.utilityService.punyHost(object.id) !== this.utilityService.punyHost(value)) {
|
|
||||||
throw new IdentifiableError('fd93c2fa-69a8-440f-880b-bf178e0ec877', `invalid AP object ${value}: id ${object.id} has different host`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,124 @@
|
||||||
*/
|
*/
|
||||||
import type { IObject } from '../type.js';
|
import type { IObject } from '../type.js';
|
||||||
|
|
||||||
export function assertActivityMatchesUrls(activity: IObject, urls: string[]) {
|
export enum FetchAllowSoftFailMask {
|
||||||
const hosts = urls.map(it => new URL(it).host);
|
// Allow no softfail flags
|
||||||
|
Strict = 0,
|
||||||
const idOk = activity.id !== undefined && hosts.includes(new URL(activity.id).host);
|
// The values in tuple (requestUrl, finalUrl, objectId) are not all identical
|
||||||
|
//
|
||||||
// technically `activity.url` could be an `ApObject = IObject |
|
// This condition is common for user-initiated lookups but should not be allowed in federation loop
|
||||||
// string | (IObject | string)[]`, but if it's a complicated thing
|
//
|
||||||
// and the `activity.id` doesn't match, I think we're fine
|
// Allow variations:
|
||||||
// rejecting the activity
|
// good example: https://alice.example.com/@user -> https://alice.example.com/user/:userId
|
||||||
const urlOk = typeof(activity.url) === 'string' && hosts.includes(new URL(activity.url).host);
|
// problematic example: https://alice.example.com/redirect?url=https://bad.example.com/ -> https://bad.example.com/ -> https://alice.example.com/somethingElse
|
||||||
|
NonCanonicalId = 1 << 0,
|
||||||
if (!idOk && !urlOk) {
|
// Allow the final object to be at most one subdomain deeper than the request URL, similar to SPF relaxed alignment
|
||||||
throw new Error(`bad Activity: neither id(${activity?.id}) nor url(${activity?.url}) match location(${urls})`);
|
//
|
||||||
}
|
// Currently no code path allows this flag to be set, but is kept in case of future use as some niche deployments do this, and we provide a pre-reviewed mechanism to opt-in.
|
||||||
|
//
|
||||||
|
// Allow variations:
|
||||||
|
// good example: https://example.com/@user -> https://activitypub.example.com/@user { id: 'https://activitypub.example.com/@user' }
|
||||||
|
// problematic example: https://example.com/@user -> https://untrusted.example.com/@user { id: 'https://untrusted.example.com/@user' }
|
||||||
|
MisalignedOrigin = 1 << 1,
|
||||||
|
// The requested URL has a different host than the returned object ID, although the final URL is still consistent with the object ID
|
||||||
|
//
|
||||||
|
// This condition is common for user-initiated lookups using an intermediate host but should not be allowed in federation loops
|
||||||
|
//
|
||||||
|
// Allow variations:
|
||||||
|
// good example: https://alice.example.com/@user@bob.example.com -> https://bob.example.com/@user { id: 'https://bob.example.com/@user' }
|
||||||
|
// problematic example: https://alice.example.com/definitelyAlice -> https://bob.example.com/@somebodyElse { id: 'https://bob.example.com/@somebodyElse' }
|
||||||
|
CrossOrigin = 1 << 2 | MisalignedOrigin,
|
||||||
|
// Allow all softfail flags
|
||||||
|
//
|
||||||
|
// do not use this flag on released code
|
||||||
|
Any = ~0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fuzz match on whether the candidate host has authority over the request host
|
||||||
|
*
|
||||||
|
* @param requestHost The host of the requested resources
|
||||||
|
* @param candidateHost The host of final response
|
||||||
|
* @returns Whether the candidate host has authority over the request host, or if a soft fail is required for a match
|
||||||
|
*/
|
||||||
|
function hostFuzzyMatch(requestHost: string, candidateHost: string): FetchAllowSoftFailMask {
|
||||||
|
const requestFqdn = requestHost.endsWith('.') ? requestHost : `${requestHost}.`;
|
||||||
|
const candidateFqdn = candidateHost.endsWith('.') ? candidateHost : `${candidateHost}.`;
|
||||||
|
|
||||||
|
if (requestFqdn === candidateFqdn) {
|
||||||
|
return FetchAllowSoftFailMask.Strict;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow only one case where candidateHost is a first-level subdomain of requestHost
|
||||||
|
const requestDnsDepth = requestFqdn.split('.').length;
|
||||||
|
const candidateDnsDepth = candidateFqdn.split('.').length;
|
||||||
|
|
||||||
|
if ((candidateDnsDepth - requestDnsDepth) !== 1) {
|
||||||
|
return FetchAllowSoftFailMask.CrossOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (`.${candidateHost}`.endsWith(`.${requestHost}`)) {
|
||||||
|
return FetchAllowSoftFailMask.MisalignedOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FetchAllowSoftFailMask.CrossOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize host names by removing www. prefix
|
||||||
|
function normalizeSynonymousSubdomain(url: URL | string): URL {
|
||||||
|
const urlParsed = url instanceof URL ? url : new URL(url);
|
||||||
|
const host = urlParsed.host;
|
||||||
|
const normalizedHost = host.replace(/^www\./, '');
|
||||||
|
return new URL(urlParsed.toString().replace(host, normalizedHost));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertActivityMatchesUrls(requestUrl: string | URL, activity: IObject, candidateUrls: (string | URL)[], allowSoftfail: FetchAllowSoftFailMask): FetchAllowSoftFailMask {
|
||||||
|
// must have a unique identifier to verify authority
|
||||||
|
if (!activity.id) {
|
||||||
|
throw new Error('bad Activity: missing id field');
|
||||||
|
}
|
||||||
|
|
||||||
|
let softfail = 0;
|
||||||
|
|
||||||
|
// if the flag is allowed, set the flag on return otherwise throw
|
||||||
|
const requireSoftfail = (needed: FetchAllowSoftFailMask, message: string) => {
|
||||||
|
if ((allowSoftfail & needed) !== needed) {
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
softfail |= needed;
|
||||||
|
};
|
||||||
|
|
||||||
|
const requestUrlParsed = normalizeSynonymousSubdomain(requestUrl);
|
||||||
|
const idParsed = normalizeSynonymousSubdomain(activity.id);
|
||||||
|
|
||||||
|
const candidateUrlsParsed = candidateUrls.map(it => normalizeSynonymousSubdomain(it));
|
||||||
|
|
||||||
|
const requestUrlSecure = requestUrlParsed.protocol === 'https:';
|
||||||
|
const finalUrlSecure = candidateUrlsParsed.every(it => it.protocol === 'https:');
|
||||||
|
if (requestUrlSecure && !finalUrlSecure) {
|
||||||
|
throw new Error(`bad Activity: id(${activity.id}) is not allowed to have http:// in the url`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare final URL to the ID
|
||||||
|
if (!candidateUrlsParsed.some(it => it.href === idParsed.href)) {
|
||||||
|
requireSoftfail(FetchAllowSoftFailMask.NonCanonicalId, `bad Activity: id(${activity.id}) does not match response url(${candidateUrlsParsed.map(it => it.toString())})`);
|
||||||
|
|
||||||
|
// at lease host need to match exactly (ActivityPub requirement)
|
||||||
|
if (!candidateUrlsParsed.some(it => idParsed.host === it.host)) {
|
||||||
|
throw new Error(`bad Activity: id(${activity.id}) does not match response host(${candidateUrlsParsed.map(it => it.host)})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare request URL to the ID
|
||||||
|
if (!requestUrlParsed.href.includes(idParsed.href)) {
|
||||||
|
requireSoftfail(FetchAllowSoftFailMask.NonCanonicalId, `bad Activity: id(${activity.id}) does not match request url(${requestUrlParsed.toString()})`);
|
||||||
|
|
||||||
|
// if cross-origin lookup is allowed, we can accept some variation between the original request URL to the final object ID (but not between the final URL and the object ID)
|
||||||
|
const hostResult = hostFuzzyMatch(requestUrlParsed.host, idParsed.host);
|
||||||
|
|
||||||
|
requireSoftfail(hostResult, `bad Activity: id(${activity.id}) is valid but is not the same origin as request url(${requestUrlParsed.toString()})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return softfail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,12 +57,14 @@ const ajv = new Ajv();
|
||||||
|
|
||||||
function isLocalUser(user: MiUser): user is MiLocalUser;
|
function isLocalUser(user: MiUser): user is MiLocalUser;
|
||||||
function isLocalUser<T extends { host: MiUser['host'] }>(user: T): user is (T & { host: null; });
|
function isLocalUser<T extends { host: MiUser['host'] }>(user: T): user is (T & { host: null; });
|
||||||
|
|
||||||
function isLocalUser(user: MiUser | { host: MiUser['host'] }): boolean {
|
function isLocalUser(user: MiUser | { host: MiUser['host'] }): boolean {
|
||||||
return user.host == null;
|
return user.host == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRemoteUser(user: MiUser): user is MiRemoteUser;
|
function isRemoteUser(user: MiUser): user is MiRemoteUser;
|
||||||
function isRemoteUser<T extends { host: MiUser['host'] }>(user: T): user is (T & { host: string; });
|
function isRemoteUser<T extends { host: MiUser['host'] }>(user: T): user is (T & { host: string; });
|
||||||
|
|
||||||
function isRemoteUser(user: MiUser | { host: MiUser['host'] }): boolean {
|
function isRemoteUser(user: MiUser | { host: MiUser['host'] }): boolean {
|
||||||
return !isLocalUser(user);
|
return !isLocalUser(user);
|
||||||
}
|
}
|
||||||
|
@ -78,7 +80,7 @@ export type UserRelation = {
|
||||||
isBlocked: boolean
|
isBlocked: boolean
|
||||||
isMuted: boolean
|
isMuted: boolean
|
||||||
isRenoteMuted: boolean
|
isRenoteMuted: boolean
|
||||||
}
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserEntityService implements OnModuleInit {
|
export class UserEntityService implements OnModuleInit {
|
||||||
|
|
|
@ -143,7 +143,7 @@ type OfSchema = {
|
||||||
readonly anyOf?: ReadonlyArray<Schema>;
|
readonly anyOf?: ReadonlyArray<Schema>;
|
||||||
readonly oneOf?: ReadonlyArray<Schema>;
|
readonly oneOf?: ReadonlyArray<Schema>;
|
||||||
readonly allOf?: ReadonlyArray<Schema>;
|
readonly allOf?: ReadonlyArray<Schema>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface Schema extends OfSchema {
|
export interface Schema extends OfSchema {
|
||||||
readonly type?: TypeStringef;
|
readonly type?: TypeStringef;
|
||||||
|
@ -217,7 +217,7 @@ type ObjectSchemaTypeDef<p extends Schema> =
|
||||||
:
|
:
|
||||||
p['anyOf'] extends ReadonlyArray<Schema> ? never : // see CONTRIBUTING.md
|
p['anyOf'] extends ReadonlyArray<Schema> ? never : // see CONTRIBUTING.md
|
||||||
p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
|
p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
|
||||||
any
|
any;
|
||||||
|
|
||||||
type ObjectSchemaType<p extends Schema> = NullOrUndefined<p, ObjectSchemaTypeDef<p>>;
|
type ObjectSchemaType<p extends Schema> = NullOrUndefined<p, ObjectSchemaTypeDef<p>>;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type JsonValue = JsonArray | JsonObject | string | number | boolean | null;
|
export type JsonValue = JsonArray | JsonObject | string | number | boolean | null;
|
||||||
export type JsonObject = {[K in string]?: JsonValue};
|
export type JsonObject = { [K in string]?: JsonValue };
|
||||||
export type JsonArray = JsonValue[];
|
export type JsonArray = JsonValue[];
|
||||||
|
|
||||||
export function isJsonObject(value: JsonValue | undefined): value is JsonObject {
|
export function isJsonObject(value: JsonValue | undefined): value is JsonObject {
|
||||||
|
|
|
@ -90,6 +90,10 @@ export type MiNotification = {
|
||||||
type: 'login';
|
type: 'login';
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
} | {
|
||||||
|
type: 'createToken';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
} | {
|
} | {
|
||||||
type: 'app';
|
type: 'app';
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -118,3 +118,5 @@ export class MiPage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const pageNameSchema = { type: 'string', pattern: /^[^\s:\/?#\[\]@!$&'()*+,;=\\%\x00-\x20]{1,256}$/.source } as const;
|
||||||
|
|
|
@ -288,24 +288,24 @@ export class MiUser {
|
||||||
export type MiLocalUser = MiUser & {
|
export type MiLocalUser = MiUser & {
|
||||||
host: null;
|
host: null;
|
||||||
uri: null;
|
uri: null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type MiPartialLocalUser = Partial<MiUser> & {
|
export type MiPartialLocalUser = Partial<MiUser> & {
|
||||||
id: MiUser['id'];
|
id: MiUser['id'];
|
||||||
host: null;
|
host: null;
|
||||||
uri: null;
|
uri: null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type MiRemoteUser = MiUser & {
|
export type MiRemoteUser = MiUser & {
|
||||||
host: string;
|
host: string;
|
||||||
uri: string;
|
uri: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type MiPartialRemoteUser = Partial<MiUser> & {
|
export type MiPartialRemoteUser = Partial<MiUser> & {
|
||||||
id: MiUser['id'];
|
id: MiUser['id'];
|
||||||
host: string;
|
host: string;
|
||||||
uri: string;
|
uri: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const;
|
export const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const;
|
||||||
export const passwordSchema = { type: 'string', minLength: 1 } as const;
|
export const passwordSchema = { type: 'string', minLength: 1 } as const;
|
||||||
|
|
|
@ -332,6 +332,16 @@ export const packedNotificationSchema = {
|
||||||
enum: ['login'],
|
enum: ['login'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
...baseSchema.properties,
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
enum: ['createToken'],
|
||||||
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
@ -92,7 +92,7 @@ const sqlLogger = dbLogger.createSubLogger('sql', 'gray');
|
||||||
export type LoggerProps = {
|
export type LoggerProps = {
|
||||||
disableQueryTruncation?: boolean;
|
disableQueryTruncation?: boolean;
|
||||||
enableQueryParamLogging?: boolean;
|
enableQueryParamLogging?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
function highlightSql(sql: string) {
|
function highlightSql(sql: string) {
|
||||||
return highlight.highlight(sql, {
|
return highlight.highlight(sql, {
|
||||||
|
|
|
@ -29,7 +29,7 @@ export type ModeratorInactivityEvaluationResult = {
|
||||||
isModeratorsInactive: boolean;
|
isModeratorsInactive: boolean;
|
||||||
inactiveModerators: MiUser[];
|
inactiveModerators: MiUser[];
|
||||||
remainingTime: ModeratorInactivityRemainingTime;
|
remainingTime: ModeratorInactivityRemainingTime;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ModeratorInactivityRemainingTime = {
|
export type ModeratorInactivityRemainingTime = {
|
||||||
time: number;
|
time: number;
|
||||||
|
|
|
@ -107,12 +107,12 @@ export class InboxProcessorService implements OnApplicationShutdown {
|
||||||
|
|
||||||
// それでもわからなければ終了
|
// それでもわからなければ終了
|
||||||
if (authUser == null) {
|
if (authUser == null) {
|
||||||
throw new Bull.UnrecoverableError('skip: failed to resolve user');
|
throw new Bull.UnrecoverableError(`skip: failed to resolve user ${getApId(activity.actor)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// publicKey がなくても終了
|
// publicKey がなくても終了
|
||||||
if (authUser.key == null) {
|
if (authUser.key == null) {
|
||||||
throw new Bull.UnrecoverableError('skip: failed to resolve user publicKey');
|
throw new Bull.UnrecoverableError(`skip: failed to resolve user publicKey ${getApId(activity.actor)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP-Signatureの検証
|
// HTTP-Signatureの検証
|
||||||
|
|
|
@ -38,7 +38,7 @@ export type RelationshipJobData = {
|
||||||
silent?: boolean;
|
silent?: boolean;
|
||||||
requestId?: string;
|
requestId?: string;
|
||||||
withReplies?: boolean;
|
withReplies?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type DbJobData<T extends keyof DbJobMap> = DbJobMap[T];
|
export type DbJobData<T extends keyof DbJobMap> = DbJobMap[T];
|
||||||
|
|
||||||
|
@ -61,11 +61,11 @@ export type DbJobMap = {
|
||||||
importUserLists: DbUserImportJobData;
|
importUserLists: DbUserImportJobData;
|
||||||
importCustomEmojis: DbUserImportJobData;
|
importCustomEmojis: DbUserImportJobData;
|
||||||
deleteAccount: DbUserDeleteJobData;
|
deleteAccount: DbUserDeleteJobData;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type DbJobDataWithUser = {
|
export type DbJobDataWithUser = {
|
||||||
user: ThinUser;
|
user: ThinUser;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type DbExportFollowingData = {
|
export type DbExportFollowingData = {
|
||||||
user: ThinUser;
|
user: ThinUser;
|
||||||
|
@ -75,7 +75,7 @@ export type DbExportFollowingData = {
|
||||||
|
|
||||||
export type DBExportAntennasData = {
|
export type DBExportAntennasData = {
|
||||||
user: ThinUser
|
user: ThinUser
|
||||||
}
|
};
|
||||||
|
|
||||||
export type DbUserDeleteJobData = {
|
export type DbUserDeleteJobData = {
|
||||||
user: ThinUser;
|
user: ThinUser;
|
||||||
|
@ -91,7 +91,7 @@ export type DbUserImportJobData = {
|
||||||
export type DBAntennaImportJobData = {
|
export type DBAntennaImportJobData = {
|
||||||
user: ThinUser,
|
user: ThinUser,
|
||||||
antenna: Antenna
|
antenna: Antenna
|
||||||
}
|
};
|
||||||
|
|
||||||
export type DbUserImportToDbJobData = {
|
export type DbUserImportToDbJobData = {
|
||||||
user: ThinUser;
|
user: ThinUser;
|
||||||
|
|
|
@ -103,6 +103,43 @@ export class ServerService implements OnApplicationShutdown {
|
||||||
serve: false,
|
serve: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// if the requester looks like to be performing an ActivityPub object lookup, reject all external redirects
|
||||||
|
//
|
||||||
|
// this will break lookup that involve copying a URL from a third-party server, like trying to lookup http://charlie.example.com/@alice@alice.com
|
||||||
|
//
|
||||||
|
// this is not required by standard but protect us from peers that did not validate final URL.
|
||||||
|
if (this.config.disallowExternalApRedirect) {
|
||||||
|
const maybeApLookupRegex = /application\/activity\+json|application\/ld\+json.+activitystreams/i;
|
||||||
|
fastify.addHook('onSend', (request, reply, _, done) => {
|
||||||
|
const location = reply.getHeader('location');
|
||||||
|
if (reply.statusCode < 300 || reply.statusCode >= 400 || typeof location !== 'string') {
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!maybeApLookupRegex.test(request.headers.accept ?? '')) {
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const effectiveLocation = process.env.NODE_ENV === 'production' ? location : location.replace(/^http:\/\//, 'https://');
|
||||||
|
if (effectiveLocation.startsWith(`https://${this.config.host}/`)) {
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.status(406);
|
||||||
|
reply.removeHeader('location');
|
||||||
|
reply.header('content-type', 'text/plain; charset=utf-8');
|
||||||
|
reply.header('link', `<${encodeURI(location)}>; rel="canonical"`);
|
||||||
|
done(null, [
|
||||||
|
"Refusing to relay remote ActivityPub object lookup.",
|
||||||
|
"",
|
||||||
|
`Please remove 'application/activity+json' and 'application/ld+json' from the Accept header or fetch using the authoritative URL at ${location}.`,
|
||||||
|
].join('\n'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fastify.register(this.apiServerService.createServer, { prefix: '/api' });
|
fastify.register(this.apiServerService.createServer, { prefix: '/api' });
|
||||||
fastify.register(this.openApiServerService.createServer);
|
fastify.register(this.openApiServerService.createServer);
|
||||||
fastify.register(this.fileServerService.createServer);
|
fastify.register(this.fileServerService.createServer);
|
||||||
|
|
|
@ -122,7 +122,7 @@ export type IEndpointMeta = (Omit<IEndpointMetaBase, 'requireCrential' | 'requir
|
||||||
}) | (Omit<IEndpointMetaBase, 'requireAdmin' | 'kind'> & {
|
}) | (Omit<IEndpointMetaBase, 'requireAdmin' | 'kind'> & {
|
||||||
requireAdmin: true,
|
requireAdmin: true,
|
||||||
kind: (typeof permissions)[number],
|
kind: (typeof permissions)[number],
|
||||||
})
|
});
|
||||||
|
|
||||||
export interface IEndpoint {
|
export interface IEndpoint {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -512,6 +512,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
federation: {
|
federation: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
enum: ['all', 'specified', 'none'],
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
federationHosts: {
|
federationHosts: {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
|
import { FetchAllowSoftFailMask } from '@/core/activitypub/misc/check-against-url.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['federation'],
|
tags: ['federation'],
|
||||||
|
@ -53,11 +54,6 @@ export const meta = {
|
||||||
code: 'RESPONSE_INVALID',
|
code: 'RESPONSE_INVALID',
|
||||||
id: '70193c39-54f3-4813-82f0-70a680f7495b',
|
id: '70193c39-54f3-4813-82f0-70a680f7495b',
|
||||||
},
|
},
|
||||||
responseInvalidIdHostNotMatch: {
|
|
||||||
message: 'Requested URI and response URI host does not match.',
|
|
||||||
code: 'RESPONSE_INVALID_ID_HOST_NOT_MATCH',
|
|
||||||
id: 'a2c9c61a-cb72-43ab-a964-3ca5fddb410a',
|
|
||||||
},
|
|
||||||
noSuchObject: {
|
noSuchObject: {
|
||||||
message: 'No such object.',
|
message: 'No such object.',
|
||||||
code: 'NO_SUCH_OBJECT',
|
code: 'NO_SUCH_OBJECT',
|
||||||
|
@ -153,7 +149,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
// リモートから一旦オブジェクトフェッチ
|
// リモートから一旦オブジェクトフェッチ
|
||||||
const resolver = this.apResolverService.createResolver();
|
const resolver = this.apResolverService.createResolver();
|
||||||
const object = await resolver.resolve(uri).catch((err) => {
|
// allow ap/show exclusively to lookup URLs that are cross-origin or non-canonical (like https://alice.example.com/@bob@bob.example.com -> https://bob.example.com/@bob)
|
||||||
|
const object = await resolver.resolve(uri, FetchAllowSoftFailMask.CrossOrigin | FetchAllowSoftFailMask.NonCanonicalId).catch((err) => {
|
||||||
if (err instanceof IdentifiableError) {
|
if (err instanceof IdentifiableError) {
|
||||||
switch (err.id) {
|
switch (err.id) {
|
||||||
// resolve
|
// resolve
|
||||||
|
@ -165,10 +162,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
case '09d79f9e-64f1-4316-9cfa-e75c4d091574':
|
case '09d79f9e-64f1-4316-9cfa-e75c4d091574':
|
||||||
throw new ApiError(meta.errors.federationNotAllowed);
|
throw new ApiError(meta.errors.federationNotAllowed);
|
||||||
case '72180409-793c-4973-868e-5a118eb5519b':
|
case '72180409-793c-4973-868e-5a118eb5519b':
|
||||||
case 'ad2dc287-75c1-44c4-839d-3d2e64576675':
|
|
||||||
throw new ApiError(meta.errors.responseInvalid);
|
throw new ApiError(meta.errors.responseInvalid);
|
||||||
case 'fd93c2fa-69a8-440f-880b-bf178e0ec877':
|
|
||||||
throw new ApiError(meta.errors.responseInvalidIdHostNotMatch);
|
|
||||||
|
|
||||||
// resolveLocal
|
// resolveLocal
|
||||||
case '02b40cd0-fa92-4b0c-acc9-fb2ada952ab8':
|
case '02b40cd0-fa92-4b0c-acc9-fb2ada952ab8':
|
||||||
|
|
|
@ -96,7 +96,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
await this.userFollowingService.unfollow(follower, followee);
|
await this.userFollowingService.unfollow(follower, followee);
|
||||||
|
|
||||||
return await this.userEntityService.pack(followee.id, me);
|
return await this.userEntityService.pack(follower.id, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { AccessTokensRepository } from '@/models/_.js';
|
import type { AccessTokensRepository } from '@/models/_.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { NotificationService } from '@/core/NotificationService.js';
|
||||||
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private accessTokensRepository: AccessTokensRepository,
|
private accessTokensRepository: AccessTokensRepository,
|
||||||
|
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
// Generate access token
|
// Generate access token
|
||||||
|
@ -71,6 +73,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
permission: ps.permission,
|
permission: ps.permission,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// アクセストークンが生成されたことを通知
|
||||||
|
this.notificationService.createNotification(me.id, 'createToken', {});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
token: accessToken,
|
token: accessToken,
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@ import ms from 'ms';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type { DriveFilesRepository, PagesRepository } from '@/models/_.js';
|
import type { DriveFilesRepository, PagesRepository } from '@/models/_.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { MiPage } from '@/models/Page.js';
|
import { MiPage, pageNameSchema } from '@/models/Page.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
@ -51,7 +51,7 @@ export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
title: { type: 'string' },
|
title: { type: 'string' },
|
||||||
name: { type: 'string', minLength: 1 },
|
name: { ...pageNameSchema, minLength: 1 },
|
||||||
summary: { type: 'string', nullable: true },
|
summary: { type: 'string', nullable: true },
|
||||||
content: { type: 'array', items: {
|
content: { type: 'array', items: {
|
||||||
type: 'object', additionalProperties: true,
|
type: 'object', additionalProperties: true,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { PagesRepository, DriveFilesRepository } from '@/models/_.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
import { pageNameSchema } from '@/models/Page.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['pages'],
|
tags: ['pages'],
|
||||||
|
@ -31,13 +32,11 @@ export const meta = {
|
||||||
code: 'NO_SUCH_PAGE',
|
code: 'NO_SUCH_PAGE',
|
||||||
id: '21149b9e-3616-4778-9592-c4ce89f5a864',
|
id: '21149b9e-3616-4778-9592-c4ce89f5a864',
|
||||||
},
|
},
|
||||||
|
|
||||||
accessDenied: {
|
accessDenied: {
|
||||||
message: 'Access denied.',
|
message: 'Access denied.',
|
||||||
code: 'ACCESS_DENIED',
|
code: 'ACCESS_DENIED',
|
||||||
id: '3c15cd52-3b4b-4274-967d-6456fc4f792b',
|
id: '3c15cd52-3b4b-4274-967d-6456fc4f792b',
|
||||||
},
|
},
|
||||||
|
|
||||||
noSuchFile: {
|
noSuchFile: {
|
||||||
message: 'No such file.',
|
message: 'No such file.',
|
||||||
code: 'NO_SUCH_FILE',
|
code: 'NO_SUCH_FILE',
|
||||||
|
@ -56,7 +55,7 @@ export const paramDef = {
|
||||||
properties: {
|
properties: {
|
||||||
pageId: { type: 'string', format: 'misskey:id' },
|
pageId: { type: 'string', format: 'misskey:id' },
|
||||||
title: { type: 'string' },
|
title: { type: 'string' },
|
||||||
name: { type: 'string', minLength: 1 },
|
name: { ...pageNameSchema, minLength: 1 },
|
||||||
summary: { type: 'string', nullable: true },
|
summary: { type: 'string', nullable: true },
|
||||||
content: { type: 'array', items: {
|
content: { type: 'array', items: {
|
||||||
type: 'object', additionalProperties: true,
|
type: 'object', additionalProperties: true,
|
||||||
|
|
|
@ -210,9 +210,15 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) {
|
||||||
|
|
||||||
spec.paths['/' + endpoint.name] = {
|
spec.paths['/' + endpoint.name] = {
|
||||||
...(endpoint.meta.allowGet ? {
|
...(endpoint.meta.allowGet ? {
|
||||||
get: info,
|
get: {
|
||||||
|
...info,
|
||||||
|
operationId: 'get___' + info.operationId,
|
||||||
|
},
|
||||||
} : {}),
|
} : {}),
|
||||||
post: info,
|
post: {
|
||||||
|
...info,
|
||||||
|
operationId: 'post___' + info.operationId,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,8 @@ export default abstract class Channel {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public send(payload: { type: string, body: JsonValue }): void
|
public send(payload: { type: string, body: JsonValue }): void;
|
||||||
public send(type: string, payload: JsonValue): void
|
public send(type: string, payload: JsonValue): void;
|
||||||
@bindThis
|
@bindThis
|
||||||
public send(typeOrPayload: { type: string, body: JsonValue } | string, payload?: JsonValue) {
|
public send(typeOrPayload: { type: string, body: JsonValue } | string, payload?: JsonValue) {
|
||||||
const type = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).type : (typeOrPayload as string);
|
const type = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).type : (typeOrPayload as string);
|
||||||
|
@ -108,4 +108,4 @@ export type MiChannelService<T extends boolean> = {
|
||||||
requireCredential: T;
|
requireCredential: T;
|
||||||
kind: T extends true ? string : string | null | undefined;
|
kind: T extends true ? string : string | null | undefined;
|
||||||
create: (id: string, connection: Connection) => Channel;
|
create: (id: string, connection: Connection) => Channel;
|
||||||
}
|
};
|
||||||
|
|
|
@ -114,13 +114,17 @@
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
|
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const locale = JSON.parse(localStorage.getItem('locale') || '{}');
|
||||||
|
|
||||||
|
const title = locale?._bootErrors?.title || 'Failed to initialize Misskey';
|
||||||
|
const reload = locale?.reload || 'Reload';
|
||||||
|
|
||||||
document.body.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M12 9v4" /><path d="M12 16v.01" /></svg>
|
document.body.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M12 9v4" /><path d="M12 16v.01" /></svg>
|
||||||
<div class="message">読み込みに失敗しました</div>
|
<div class="message">${title}</div>
|
||||||
<div class="submessage">Failed to initialize Misskey</div>
|
|
||||||
<div class="submessage">Error Code: ${code}</div>
|
<div class="submessage">Error Code: ${code}</div>
|
||||||
<button onclick="location.reload(!0)">
|
<button onclick="location.reload(!0)">
|
||||||
<div>リロード</div>
|
<div>${reload}</div>
|
||||||
<div><small>Reload</small></div>
|
|
||||||
</button>`;
|
</button>`;
|
||||||
addStyle(`
|
addStyle(`
|
||||||
#misskey_app,
|
#misskey_app,
|
||||||
|
|
|
@ -151,6 +151,22 @@
|
||||||
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
|
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const locale = JSON.parse(localStorage.getItem('locale') || '{}');
|
||||||
|
|
||||||
|
const messages = Object.assign({
|
||||||
|
title: 'Failed to initialize Misskey',
|
||||||
|
solution: 'The following actions may solve the problem.',
|
||||||
|
solution1: 'Update your os and browser',
|
||||||
|
solution2: 'Disable an adblocker',
|
||||||
|
solution3: 'Clear the browser cache',
|
||||||
|
solution4: '(Tor Browser) Set dom.webaudio.enabled to true',
|
||||||
|
otherOption: 'Other options',
|
||||||
|
otherOption1: 'Clear preferences and cache',
|
||||||
|
otherOption2: 'Start the simple client',
|
||||||
|
otherOption3: 'Start the repair tool',
|
||||||
|
}, locale?._bootErrors || {});
|
||||||
|
const reload = locale?.reload || 'Reload';
|
||||||
|
|
||||||
let errorsElement = document.getElementById('errors');
|
let errorsElement = document.getElementById('errors');
|
||||||
|
|
||||||
if (!errorsElement) {
|
if (!errorsElement) {
|
||||||
|
@ -160,32 +176,32 @@
|
||||||
<path d="M12 9v2m0 4v.01"></path>
|
<path d="M12 9v2m0 4v.01"></path>
|
||||||
<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
|
<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
|
||||||
</svg>
|
</svg>
|
||||||
<h1>Failed to load<br>読み込みに失敗しました</h1>
|
<h1>${messages.title}</h1>
|
||||||
<button class="button-big" onclick="location.reload(true);">
|
<button class="button-big" onclick="location.reload(true);">
|
||||||
<span class="button-label-big">Reload / リロード</span>
|
<span class="button-label-big">${reload}</span>
|
||||||
</button>
|
</button>
|
||||||
<p><b>The following actions may solve the problem. / 以下を行うと解決する可能性があります。</b></p>
|
<p><b>${messages.solution}</b></p>
|
||||||
<p>Update your os and browser / ブラウザおよびOSを最新バージョンに更新する</p>
|
<p>${messages.solution1}</p>
|
||||||
<p>Disable an adblocker / アドブロッカーを無効にする</p>
|
<p>${messages.solution2}</p>
|
||||||
<p>Clear the browser cache / ブラウザのキャッシュをクリアする</p>
|
<p>${messages.solution3}</p>
|
||||||
<p>(Tor Browser) Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する</p>
|
<p>${messages.solution4}</p>
|
||||||
<details style="color: #86b300;">
|
<details style="color: #86b300;">
|
||||||
<summary>Other options / その他のオプション</summary>
|
<summary>${messages.otherOption}</summary>
|
||||||
<a href="/flush">
|
<a href="/flush">
|
||||||
<button class="button-small">
|
<button class="button-small">
|
||||||
<span class="button-label-small">Clear preferences and cache</span>
|
<span class="button-label-small">${messages.otherOption1}</span>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
<br>
|
<br>
|
||||||
<a href="/cli">
|
<a href="/cli">
|
||||||
<button class="button-small">
|
<button class="button-small">
|
||||||
<span class="button-label-small">Start the simple client</span>
|
<span class="button-label-small">${messages.otherOption2}</span>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
<br>
|
<br>
|
||||||
<a href="/bios">
|
<a href="/bios">
|
||||||
<button class="button-small">
|
<button class="button-small">
|
||||||
<span class="button-label-small">Start the repair tool</span>
|
<span class="button-label-small">${messages.otherOption3}</span>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
</details>
|
</details>
|
||||||
|
|
|
@ -5,112 +5,107 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
* {
|
* {
|
||||||
font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
|
font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
#misskey_app,
|
#misskey_app,
|
||||||
#splash {
|
#splash {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
body,
|
body,
|
||||||
html {
|
html {
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
color: #dfddcc;
|
color: #dfddcc;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
padding: 0px 12px 0px 12px;
|
padding: 0px 12px 0px 12px;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-big {
|
.button-big {
|
||||||
background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
|
background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-big:hover {
|
.button-big:hover {
|
||||||
background: rgb(153, 204, 0);
|
background: rgb(153, 204, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-small {
|
.button-small {
|
||||||
background: #444;
|
background: #444;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-small:hover {
|
.button-small:hover {
|
||||||
background: #555;
|
background: #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-label-big {
|
.button-label-big {
|
||||||
color: #222;
|
color: #222;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 20px;
|
font-size: 1.2em;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-label-small {
|
.button-label-small {
|
||||||
color: rgb(153, 204, 0);
|
color: rgb(153, 204, 0);
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: rgb(134, 179, 0);
|
color: rgb(134, 179, 0);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
p,
|
p,
|
||||||
li {
|
li {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
|
||||||
|
|
||||||
.dont-worry,
|
|
||||||
#msg {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-warning {
|
.icon-warning {
|
||||||
color: #dec340;
|
color: #dec340;
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
padding-top: 2rem;
|
padding-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 32px;
|
font-size: 1.5em;
|
||||||
|
margin: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
display: block;
|
display: block;
|
||||||
font-family: Fira, FiraCode, monospace;
|
font-family: Fira, FiraCode, monospace;
|
||||||
background: #333;
|
background: #333;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
max-width: 40rem;
|
max-width: 40rem;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
summary {
|
#errorInfo summary {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
summary > * {
|
#errorInfo summary>* {
|
||||||
display: inline;
|
display: inline;
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 500px) {
|
@media screen and (max-width: 500px) {
|
||||||
details {
|
#errorInfo {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const locale = JSON.parse(localStorage.getItem('locale') || '{}');
|
||||||
|
|
||||||
|
const messages = Object.assign({
|
||||||
|
title: 'Failed to initialize Misskey',
|
||||||
|
serverError: 'If reloading after a period of time does not resolve the problem, contact the server administrator with the following ERROR ID.',
|
||||||
|
solution: 'The following actions may solve the problem.',
|
||||||
|
solution1: 'Update your os and browser',
|
||||||
|
solution2: 'Disable an adblocker',
|
||||||
|
solution3: 'Clear the browser cache',
|
||||||
|
solution4: '(Tor Browser) Set dom.webaudio.enabled to true',
|
||||||
|
otherOption: 'Other options',
|
||||||
|
otherOption1: 'Clear preferences and cache',
|
||||||
|
otherOption2: 'Start the simple client',
|
||||||
|
otherOption3: 'Start the repair tool',
|
||||||
|
}, locale?._bootErrors || {});
|
||||||
|
const reload = locale?.reload || 'Reload';
|
||||||
|
|
||||||
|
const reloadEls = document.querySelectorAll('[data-i18n-reload]');
|
||||||
|
for (const el of reloadEls) {
|
||||||
|
el.textContent = reload;
|
||||||
|
}
|
||||||
|
|
||||||
|
const i18nEls = document.querySelectorAll('[data-i18n]');
|
||||||
|
for (const el of i18nEls) {
|
||||||
|
const key = el.dataset.i18n;
|
||||||
|
if (key && messages[key]) {
|
||||||
|
el.textContent = messages[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
|
@ -2,15 +2,15 @@ doctype html
|
||||||
|
|
||||||
//
|
//
|
||||||
-
|
-
|
||||||
_____ _ _
|
_____ _ _
|
||||||
| |_|___ ___| |_ ___ _ _
|
| |_|___ ___| |_ ___ _ _
|
||||||
| | | | |_ -|_ -| '_| -_| | |
|
| | | | |_ -|_ -| '_| -_| | |
|
||||||
|_|_|_|_|___|___|_,_|___|_ |
|
|_|_|_|_|___|___|_,_|___|_ |
|
||||||
|___|
|
|___|
|
||||||
Thank you for using Misskey!
|
Thank you for using Misskey!
|
||||||
If you are reading this message... how about joining the development?
|
If you are reading this message... how about joining the development?
|
||||||
https://github.com/misskey-dev/misskey
|
https://github.com/misskey-dev/misskey
|
||||||
|
|
||||||
|
|
||||||
html
|
html
|
||||||
|
|
||||||
|
@ -27,39 +27,45 @@ html
|
||||||
style
|
style
|
||||||
include ../error.css
|
include ../error.css
|
||||||
|
|
||||||
|
script
|
||||||
|
include ../error.js
|
||||||
|
|
||||||
body
|
body
|
||||||
svg.icon-warning(xmlns="http://www.w3.org/2000/svg", viewBox="0 0 24 24", stroke-width="2", stroke="currentColor", fill="none", stroke-linecap="round", stroke-linejoin="round")
|
svg.icon-warning(xmlns="http://www.w3.org/2000/svg", viewBox="0 0 24 24", stroke-width="2", stroke="currentColor", fill="none", stroke-linecap="round", stroke-linejoin="round")
|
||||||
path(stroke="none", d="M0 0h24v24H0z", fill="none")
|
path(stroke="none", d="M0 0h24v24H0z", fill="none")
|
||||||
path(d="M12 9v2m0 4v.01")
|
path(d="M12 9v2m0 4v.01")
|
||||||
path(d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75")
|
path(d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75")
|
||||||
|
|
||||||
h1 An error has occurred!
|
h1(data-i18n="title") Failed to initialize Misskey
|
||||||
|
|
||||||
button.button-big(onclick="location.reload();")
|
button.button-big(onclick="location.reload();")
|
||||||
span.button-label-big Refresh
|
span.button-label-big(data-i18n-reload) Reload
|
||||||
|
|
||||||
p.dont-worry Don't worry, it's (probably) not your fault.
|
p(data-i18n="serverError") If reloading after a period of time does not resolve the problem, contact the server administrator with the following ERROR ID.
|
||||||
|
|
||||||
p If reloading after a period of time does not resolve the problem, contact the server administrator with the following ERROR ID.
|
|
||||||
|
|
||||||
div#errors
|
div#errors
|
||||||
code.
|
code.
|
||||||
ERROR CODE: #{code}
|
ERROR CODE: #{code}
|
||||||
ERROR ID: #{id}
|
ERROR ID: #{id}
|
||||||
|
|
||||||
p You may also try the following options:
|
p
|
||||||
|
b(data-i18n="solution") The following actions may solve the problem.
|
||||||
|
|
||||||
p Update your os and browser.
|
p(data-i18n="solution1") Update your os and browser
|
||||||
p Disable an adblocker.
|
p(data-i18n="solution2") Disable an adblocker
|
||||||
|
p(data-i18n="solution3") Clear your browser cache
|
||||||
|
p(data-i18n="solution4") (Tor Browser) Set dom.webaudio.enabled to true
|
||||||
|
|
||||||
a(href="/flush")
|
details(style="color: #86b300;")
|
||||||
button.button-small
|
summary(data-i18n="otherOption") Other options
|
||||||
span.button-label-small Clear preferences and cache
|
a(href="/flush")
|
||||||
br
|
button.button-small
|
||||||
a(href="/cli")
|
span.button-label-small(data-i18n="otherOption1") Clear preferences and cache
|
||||||
button.button-small
|
br
|
||||||
span.button-label-small Start the simple client
|
a(href="/cli")
|
||||||
br
|
button.button-small
|
||||||
a(href="/bios")
|
span.button-label-small(data-i18n="otherOption2") Start the simple client
|
||||||
button.button-small
|
br
|
||||||
span.button-label-small Start the repair tool
|
a(href="/bios")
|
||||||
|
button.button-small
|
||||||
|
span.button-label-small(data-i18n="otherOption3") Start the repair tool
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
* achievementEarned - 実績を獲得
|
* achievementEarned - 実績を獲得
|
||||||
* exportCompleted - エクスポートが完了
|
* exportCompleted - エクスポートが完了
|
||||||
* login - ログイン
|
* login - ログイン
|
||||||
|
* createToken - トークン作成
|
||||||
* app - アプリ通知
|
* app - アプリ通知
|
||||||
* test - テスト通知(サーバー側)
|
* test - テスト通知(サーバー側)
|
||||||
*/
|
*/
|
||||||
|
@ -36,6 +37,7 @@ export const notificationTypes = [
|
||||||
'achievementEarned',
|
'achievementEarned',
|
||||||
'exportCompleted',
|
'exportCompleted',
|
||||||
'login',
|
'login',
|
||||||
|
'createToken',
|
||||||
'app',
|
'app',
|
||||||
'test',
|
'test',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
|
@ -22,7 +22,7 @@ export type LoginUser = SigninResponse & {
|
||||||
client: Misskey.api.APIClient;
|
client: Misskey.api.APIClient;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** used for avoiding overload and some endpoints */
|
/** used for avoiding overload and some endpoints */
|
||||||
export type Request = <
|
export type Request = <
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue