Revert "Upstream 20240517"

This commit is contained in:
KMY(雪あすか) 2024-05-24 08:15:12 +09:00 committed by GitHub
parent 9c006fd893
commit f6dec44e95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2347 changed files with 26470 additions and 87494 deletions

View file

@ -1,9 +1,7 @@
[production]
defaults
> 0.2%
ios >= 15.6
not IE 11
not dead
not OperaMini all
[development]
supports es6-module

View file

@ -1,8 +0,0 @@
---
ignore:
# devise-two-factor advisory about brute-forcing TOTP
# We have rate-limits on authentication endpoints in place (including second
# factor verification) since Mastodon v3.2.0
- CVE-2024-0227
- CVE-2024-27456
- CVE-2023-51774

View file

@ -70,7 +70,7 @@ services:
hard: -1
libretranslate:
image: libretranslate/libretranslate:v1.5.7
image: libretranslate/libretranslate:v1.5.3
restart: unless-stopped
volumes:
- lt-data:/home/libretranslate/.local

View file

@ -1,4 +0,0 @@
# Required by ActiveRecord encryption feature
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=fkSxKD2bF396kdQbrP1EJ7WbU7ZgNokR
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=r0hvVmzBVsjxC7AMlwhOzmtc36ZCOS1E
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=PhdFyyfy5xJ7WVd2lWBpcPScRQHzRTNr

View file

@ -3,10 +3,3 @@ NODE_ENV=production
# Federation
LOCAL_DOMAIN=cb6e6126.ngrok.io
LOCAL_HTTPS=true
# Elasticsearch
ES_PREFIX=test
# Required by ActiveRecord encryption feature
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=fkSxKD2bF396kdQbrP1EJ7WbU7ZgNokR
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=r0hvVmzBVsjxC7AMlwhOzmtc36ZCOS1E
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=PhdFyyfy5xJ7WVd2lWBpcPScRQHzRTNr

View file

@ -123,7 +123,7 @@ module.exports = defineConfig({
'react/react-in-jsx-scope': 'off', // not needed with new JSX transform
'react/self-closing-comp': 'error',
// recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.8.0/src/index.js#L46
// recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/index.js
'jsx-a11y/accessible-emoji': 'warn',
'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/label-has-associated-control': 'off',
@ -165,7 +165,7 @@ module.exports = defineConfig({
// },
// ],
'jsx-a11y/no-noninteractive-tabindex': 'off',
'jsx-a11y/no-onchange': 'off',
'jsx-a11y/no-onchange': 'warn',
// recommended is full 'error'
'jsx-a11y/no-static-element-interactions': [
'warn',
@ -176,7 +176,7 @@ module.exports = defineConfig({
},
],
// See https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/config/recommended.js
// See https://github.com/import-js/eslint-plugin-import/blob/main/config/recommended.js
'import/extensions': [
'error',
'always',
@ -338,6 +338,7 @@ module.exports = defineConfig({
'plugin:import/typescript',
'plugin:promise/recommended',
'plugin:jsdoc/recommended-typescript',
'plugin:prettier/recommended',
],
parserOptions: {
@ -346,9 +347,6 @@ module.exports = defineConfig({
},
rules: {
// Disable formatting rules that have been enabled in the base config
'indent': 'off',
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
@ -363,7 +361,6 @@ module.exports = defineConfig({
"message": "Use typed hooks `useAppDispatch` and `useAppSelector` instead."
}
],
"@typescript-eslint/restrict-template-expressions": ['warn', { allowNumber: true }],
'jsdoc/require-jsdoc': 'off',
// Those rules set stricter rules for TS files

1
.github/FUNDING.yml vendored
View file

@ -1 +0,0 @@
custom: https://fantia.jp/fanclubs/484677

View file

@ -1,74 +0,0 @@
name: バグ報告
description: kmyblueのバグ報告ただし情報改竄、秘密情報の漏洩、システムの破損などが発生するバグは、こちらではなく「Security」タブよりセキュリティインシデントとして報告してください
labels: [bug]
body:
- type: textarea
attributes:
label: バグの再現手順
description: どのように操作したらバグが発生したのか、バグが発生する直前までの手順を順番に詳しく教えてください
value: |
1.
2.
3.
...
validations:
required: true
- type: textarea
attributes:
label: 期待する動作
description: どのように動いてほしかったですか?
validations:
required: true
- type: textarea
attributes:
label: 実際の動作
description: どのようなバグが発生しましたか?
validations:
required: true
- type: textarea
attributes:
label: 詳しい情報
validations:
required: false
- type: input
attributes:
label: バグが発生したkmyblueサーバーのドメイン
description: サーバー固有の問題の可能性もありますので、プライバシー上可能な範囲内で、できるだけ書いてください
placeholder: kmy.blue
validations:
required: false
- type: input
attributes:
label: バグが発生したkmyblueのバージョン
description: |
Mastodonではなくkmyblueのバージョンを記述してください。例えばバージョン表記が `v4.2.0+kmyblue.5.1-LTS` の場合、バージョンは `5.1`になります
バージョンは、PCだと画面左下、スマホだと概要画面の一番下に書いてあります
placeholder: '5.1'
validations:
required: true
- type: input
attributes:
label: ブラウザの名前
description: |
ブラウザの名前を書いてください。可能であればバージョンも併記してください
placeholder: Firefox 105.0.3
validations:
required: false
- type: input
attributes:
label: OS
description: |
あなたのOSと、できればバージョンも教えてください。スマホの場合は、「Android」「iPhone」にバージョンをつけてください
placeholder: Windows11
validations:
required: false
- type: textarea
attributes:
label: その他の詳細情報
description: |
あなたの環境が特殊な場合、詳しいことを教えてください(例: VPS、tor、学内LANなど
サーバー管理者の場合は、Ruby、Node.jsのバージョン、Cloudflareの使用可否なども可能なら書いてください
validations:
required: false

View file

@ -0,0 +1,76 @@
name: Bug Report (Web Interface)
description: If you are using Mastodon's web interface and something is not working as expected
labels: [bug, 'status/to triage', 'area/web interface']
body:
- type: markdown
attributes:
value: |
Make sure that you are submitting a new bug that was not previously reported or already fixed.
Please use a concise and distinct title for the issue.
- type: textarea
attributes:
label: Steps to reproduce the problem
description: What were you trying to do?
value: |
1.
2.
3.
...
validations:
required: true
- type: input
attributes:
label: Expected behaviour
description: What should have happened?
validations:
required: true
- type: input
attributes:
label: Actual behaviour
description: What happened?
validations:
required: true
- type: textarea
attributes:
label: Detailed description
validations:
required: false
- type: input
attributes:
label: Mastodon instance
description: The address of the Mastodon instance where you experienced the issue
placeholder: mastodon.social
validations:
required: true
- type: input
attributes:
label: Mastodon version
description: |
This is displayed at the bottom of the About page, eg. `v4.1.2+nightly-20230627`
placeholder: v4.1.2
validations:
required: true
- type: input
attributes:
label: Browser name and version
description: |
What browser are you using when getting this bug? Please specify the version as well.
placeholder: Firefox 105.0.3
validations:
required: true
- type: input
attributes:
label: Operating system
description: |
What OS are you running? Please specify the version as well.
placeholder: macOS 13.4.1
validations:
required: true
- type: textarea
attributes:
label: Technical details
description: |
Any additional technical details you may have. This can include the full error log, inspector's output…
validations:
required: false

View file

@ -1,16 +0,0 @@
name: 機能要望
description: 機能の提案
labels: [enhancement]
body:
- type: textarea
attributes:
label: 欲しい機能
description: 欲しい機能の詳細を書いてください
validations:
required: true
- type: textarea
attributes:
label: 必要性
description: この機能はあなたにとってなぜ必要でしょうか?どういった状況で使われるものですか?
validations:
required: true

View file

@ -0,0 +1,65 @@
name: Bug Report (server / API)
description: |
If something is not working as expected, but is not from using the web interface.
labels: [bug, 'status/to triage']
body:
- type: markdown
attributes:
value: |
Make sure that you are submitting a new bug that was not previously reported or already fixed.
Please use a concise and distinct title for the issue.
- type: textarea
attributes:
label: Steps to reproduce the problem
description: What were you trying to do?
value: |
1.
2.
3.
...
validations:
required: true
- type: input
attributes:
label: Expected behaviour
description: What should have happened?
validations:
required: true
- type: input
attributes:
label: Actual behaviour
description: What happened?
validations:
required: true
- type: textarea
attributes:
label: Detailed description
validations:
required: false
- type: input
attributes:
label: Mastodon instance
description: The address of the Mastodon instance where you experienced the issue
placeholder: mastodon.social
validations:
required: false
- type: input
attributes:
label: Mastodon version
description: |
This is displayed at the bottom of the About page, eg. `v4.1.2+nightly-20230627`
placeholder: v4.1.2
validations:
required: false
- type: textarea
attributes:
label: Technical details
description: |
Any additional technical details you may have, like logs or error traces
value: |
If this is happening on your own Mastodon server, please fill out those:
- Ruby version: (from `ruby --version`, eg. v3.1.2)
- Node.js version: (from `node --version`, eg. v18.16.0)
validations:
required: false

View file

@ -0,0 +1,22 @@
name: Feature Request
description: I have a suggestion
labels: [suggestion]
body:
- type: markdown
attributes:
value: |
Please use a concise and distinct title for the issue.
Consider: Could it be implemented as a 3rd party app using the REST API instead?
- type: textarea
attributes:
label: Pitch
description: Describe your idea for a feature. Make sure it has not already been suggested/implemented/turned down before.
validations:
required: true
- type: textarea
attributes:
label: Motivation
description: Why do you think this feature is needed? Who would benefit from it?
validations:
required: true

View file

@ -1,28 +0,0 @@
name: 仕様変更・改善要望
description: 既存の仕様や挙動変更の要望
labels: [specchange]
body:
- type: markdown
attributes:
value: 意図したものとは明らかに異なる挙動をしているものはバグとして、もともと仕様として決められた動きをしているものを変更したいときはこちらでお願いします
- type: textarea
attributes:
label: 挙動を変更してほしい機能や動作
validations:
required: true
- type: textarea
attributes:
label: 現在の挙動
validations:
required: true
- type: textarea
attributes:
label: 変更してほしい新しい挙動
validations:
required: true
- type: textarea
attributes:
label: 必要性
description: この変更はあなたにとってなぜ必要でしょうか?どういった状況で使われるものですか?
validations:
required: true

View file

@ -1 +1,5 @@
blank_issues_enabled: true
blank_issues_enabled: false
contact_links:
- name: GitHub Discussions
url: https://github.com/mastodon/mastodon/discussions
about: Please ask and answer questions here.

View file

@ -23,7 +23,7 @@ runs:
shell: bash
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
- uses: actions/cache@v3
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}

4
.github/codecov.yml vendored
View file

@ -1,4 +1,3 @@
comment: false # Do not leave PR comments
coverage:
status:
project:
@ -9,3 +8,6 @@ coverage:
default:
# Github status check is not blocking
informational: true
comment:
# Only write a comment in PR if there are changes
require_changes: true

View file

@ -125,29 +125,6 @@
],
groupName: null, // We dont want them to belong to any group
},
{
// Group all RuboCop packages with `rubocop` in the same PR
matchManagers: ['bundler'],
matchPackageNames: ['rubocop'],
matchPackagePrefixes: ['rubocop-'],
matchUpdateTypes: ['patch', 'minor'],
groupName: 'RuboCop (non-major)',
},
{
// Group all RSpec packages with `rspec` in the same PR
matchManagers: ['bundler'],
matchPackageNames: ['rspec'],
matchPackagePrefixes: ['rspec-'],
matchUpdateTypes: ['patch', 'minor'],
groupName: 'RSpec (non-major)',
},
{
// Group all opentelemetry-ruby packages in the same PR
matchManagers: ['bundler'],
matchPackagePrefixes: ['opentelemetry-'],
matchUpdateTypes: ['patch', 'minor'],
groupName: 'opentelemetry-ruby (non-major)',
},
// Add labels depending on package manager
{ matchManagers: ['npm', 'nvm'], addLabels: ['javascript'] },
{ matchManagers: ['bundler', 'ruby-version'], addLabels: ['ruby'] },

21
.github/stylelint-matcher.json vendored Normal file
View file

@ -0,0 +1,21 @@
{
"problemMatcher": [
{
"owner": "stylelint",
"pattern": [
{
"regexp": "^([^\\s].*)$",
"file": 1
},
{
"regexp": "^\\s+((\\d+):(\\d+))?\\s+(✖|×)\\s+(.*)\\s{2,}(.*)$",
"line": 2,
"column": 3,
"message": 5,
"code": 6,
"loop": true
}
]
}
]
}

View file

@ -0,0 +1,102 @@
on:
workflow_call:
inputs:
platforms:
required: true
type: string
cache:
type: boolean
default: true
use_native_arm64_builder:
type: boolean
push_to_images:
type: string
version_prerelease:
type: string
version_metadata:
type: string
flavor:
type: string
tags:
type: string
labels:
type: string
file_to_build:
type: string
jobs:
build-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v3
if: contains(inputs.platforms, 'linux/arm64') && !inputs.use_native_arm64_builder
- uses: docker/setup-buildx-action@v3
id: buildx
if: ${{ !(inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64')) }}
- name: Start a local Docker Builder
if: inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64')
run: |
docker run --rm -d --name buildkitd -p 1234:1234 --privileged moby/buildkit:latest --addr tcp://0.0.0.0:1234
- uses: docker/setup-buildx-action@v3
id: buildx-native
if: inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64')
with:
driver: remote
endpoint: tcp://localhost:1234
platforms: linux/amd64
append: |
- endpoint: tcp://${{ vars.DOCKER_BUILDER_HETZNER_ARM64_01_HOST }}:13865
platforms: linux/arm64
name: mastodon-docker-builder-arm64-01
driver-opts:
- servername=mastodon-docker-builder-arm64-01
env:
BUILDER_NODE_1_AUTH_TLS_CACERT: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_CACERT }}
BUILDER_NODE_1_AUTH_TLS_CERT: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_CERT }}
BUILDER_NODE_1_AUTH_TLS_KEY: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_KEY }}
- name: Log in to Docker Hub
if: contains(inputs.push_to_images, 'tootsuite')
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to the Github Container registry
if: contains(inputs.push_to_images, 'ghcr.io')
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v5
id: meta
if: ${{ inputs.push_to_images != '' }}
with:
images: ${{ inputs.push_to_images }}
flavor: ${{ inputs.flavor }}
tags: ${{ inputs.tags }}
labels: ${{ inputs.labels }}
- uses: docker/build-push-action@v5
with:
context: .
file: ${{ inputs.file_to_build }}
build-args: |
MASTODON_VERSION_PRERELEASE=${{ inputs.version_prerelease }}
MASTODON_VERSION_METADATA=${{ inputs.version_metadata }}
platforms: ${{ inputs.platforms }}
provenance: false
builder: ${{ steps.buildx.outputs.name || steps.buildx-native.outputs.name }}
push: ${{ inputs.push_to_images != '' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: ${{ inputs.cache && 'type=gha' || '' }}
cache-to: ${{ inputs.cache && 'type=gha,mode=max' || '' }}

View file

@ -1,6 +1,8 @@
name: Build security nightly container image
name: Build nightly container image
on:
workflow_dispatch:
schedule:
- cron: '0 2 * * *' # run at 2 AM UTC
permissions:
contents: read
@ -15,7 +17,7 @@ jobs:
env:
TZ: Etc/UTC
run: |
echo mastodon_version_prerelease=nightly.$(date --date='next day' +'%Y-%m-%d')-security>> $GITHUB_OUTPUT
echo mastodon_version_prerelease=nightly.$(date +'%Y-%m-%d')>> $GITHUB_OUTPUT
outputs:
prerelease: ${{ steps.version_vars.outputs.mastodon_version_prerelease }}
@ -38,7 +40,7 @@ jobs:
tags: |
type=raw,value=edge
type=raw,value=nightly
type=raw,value=${{ needs.compute-suffix.outputs.prerelease }}
type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }}
secrets: inherit
build-image-streaming:
@ -60,5 +62,5 @@ jobs:
tags: |
type=raw,value=edge
type=raw,value=nightly
type=raw,value=${{ needs.compute-suffix.outputs.prerelease }}
type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }}
secrets: inherit

58
.github/workflows/build-push-pr.yml vendored Normal file
View file

@ -0,0 +1,58 @@
name: Build container image for PR
on:
pull_request:
types: [labeled, synchronize, reopened, ready_for_review, opened]
permissions:
contents: read
packages: write
jobs:
compute-suffix:
runs-on: ubuntu-latest
# This is only allowed to run if:
# - the PR branch is in the `mastodon/mastodon` repository
# - the PR is not a draft
# - the PR has the "build-image" label
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && !github.event.pull_request.draft && contains(github.event.pull_request.labels.*.name, 'build-image') }}
steps:
# Repository needs to be cloned so `git rev-parse` below works
- name: Clone repository
uses: actions/checkout@v4
- id: version_vars
run: |
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT
outputs:
metadata: ${{ steps.version_vars.outputs.mastodon_version_metadata }}
build-image:
needs: compute-suffix
uses: ./.github/workflows/build-container-image.yml
with:
file_to_build: Dockerfile
platforms: linux/amd64,linux/arm64
use_native_arm64_builder: true
push_to_images: |
ghcr.io/mastodon/mastodon
version_metadata: ${{ needs.compute-suffix.outputs.metadata }}
flavor: |
latest=auto
tags: |
type=ref,event=pr
secrets: inherit
build-image-streaming:
needs: compute-suffix
uses: ./.github/workflows/build-container-image.yml
with:
file_to_build: streaming/Dockerfile
platforms: linux/amd64,linux/arm64
use_native_arm64_builder: true
push_to_images: |
ghcr.io/mastodon/mastodon-streaming
version_metadata: ${{ needs.compute-suffix.outputs.metadata }}
flavor: |
latest=auto
tags: |
type=ref,event=pr
secrets: inherit

51
.github/workflows/build-releases.yml vendored Normal file
View file

@ -0,0 +1,51 @@
name: Build container release images
on:
push:
tags:
- '*'
permissions:
contents: read
packages: write
jobs:
build-image:
uses: ./.github/workflows/build-container-image.yml
with:
file_to_build: Dockerfile
platforms: linux/amd64,linux/arm64
use_native_arm64_builder: true
push_to_images: |
tootsuite/mastodon
ghcr.io/mastodon/mastodon
# Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages
cache: false
# Only tag with latest when ran against the latest stable branch
# This needs to be updated after each minor version release
flavor: |
latest=${{ startsWith(github.ref, 'refs/tags/v4.2.') }}
tags: |
type=pep440,pattern={{raw}}
type=pep440,pattern=v{{major}}.{{minor}}
secrets: inherit
build-image-streaming:
if: startsWith(github.ref, 'refs/tags/v4.3.')
uses: ./.github/workflows/build-container-image.yml
with:
file_to_build: streaming/Dockerfile
platforms: linux/amd64,linux/arm64
use_native_arm64_builder: true
push_to_images: |
tootsuite/mastodon-streaming
ghcr.io/mastodon/mastodon-streaming
# Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages
cache: false
# Only tag with latest when ran against the latest stable branch
# This needs to be updated after each minor version release
flavor: |
latest=${{ startsWith(github.ref, 'refs/tags/v4.3.') }}
tags: |
type=pep440,pattern={{raw}}
type=pep440,pattern=v{{major}}.{{minor}}
secrets: inherit

71
.github/workflows/crowdin-download.yml vendored Normal file
View file

@ -0,0 +1,71 @@
name: Crowdin / Download translations
on:
schedule:
- cron: '17 4 * * *' # Every day
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
download-translations:
runs-on: ubuntu-latest
if: github.repository == 'mastodon/mastodon'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Increase Git http.postBuffer
# This is needed due to a bug in Ubuntu's cURL version?
# See https://github.com/orgs/community/discussions/55820
run: |
git config --global http.version HTTP/1.1
git config --global http.postBuffer 157286400
# Download the translation files from Crowdin
- name: crowdin action
uses: crowdin/github-action@v1
with:
upload_sources: false
upload_translations: false
download_translations: true
crowdin_branch_name: main
push_translations: false
create_pull_request: false
env:
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
# As the files are extracted from a Docker container, they belong to root:root
# We need to fix this before the next steps
- name: Fix file permissions
run: sudo chown -R runner:docker .
# This is needed to run the normalize step
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Run i18n normalize task
run: bundle exec i18n-tasks normalize
# Create or update the pull request
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5.0.2
with:
commit-message: 'New Crowdin translations'
title: 'New Crowdin Translations (automated)'
author: 'GitHub Actions <noreply@github.com>'
body: |
New Crowdin translations, automated with Github Actions
See `.github/workflows/crowdin-download.yml`
This PR will be updated every day with new translations.
Due to a limitation in Github Actions, checks are not running on this PR without manual action.
If you want to run the checks, then close and re-open it.
branch: i18n/crowdin/translations
base: main
labels: i18n

35
.github/workflows/crowdin-upload.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: Crowdin / Upload translations
on:
push:
branches:
- main
paths:
- crowdin.yml
- app/javascript/mastodon/locales/en.json
- config/locales/en.yml
- config/locales/simple_form.en.yml
- config/locales/activerecord.en.yml
- config/locales/devise.en.yml
- config/locales/doorkeeper.en.yml
- .github/workflows/crowdin-upload.yml
jobs:
upload-translations:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: crowdin action
uses: crowdin/github-action@v1
with:
upload_sources: true
upload_translations: false
download_translations: false
crowdin_branch_name: main
env:
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

View file

@ -1,18 +0,0 @@
name: Check formatting
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Check formatting with Prettier
run: yarn format:check

View file

@ -38,5 +38,9 @@ jobs:
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- uses: xt0rted/stylelint-problem-matcher@v1
- run: echo "::add-matcher::.github/stylelint-matcher.json"
- name: Stylelint
run: yarn lint:css -f github
run: yarn lint:sass

View file

@ -36,4 +36,4 @@ jobs:
- name: Run haml-lint
run: |
echo "::add-matcher::.github/workflows/haml-lint-problem-matcher.json"
bundle exec haml-lint --reporter github
bundle exec haml-lint

38
.github/workflows/lint-json.yml vendored Normal file
View file

@ -0,0 +1,38 @@
name: JSON Linting
on:
push:
branches-ignore:
- 'dependabot/**'
- 'renovate/**'
paths:
- 'package.json'
- 'yarn.lock'
- '.nvmrc'
- '.prettier*'
- '**/*.json'
- '.github/workflows/lint-json.yml'
- '!app/javascript/mastodon/locales/*.json'
pull_request:
paths:
- 'package.json'
- 'yarn.lock'
- '.nvmrc'
- '.prettier*'
- '**/*.json'
- '.github/workflows/lint-json.yml'
- '!app/javascript/mastodon/locales/*.json'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Prettier
run: yarn lint:json

38
.github/workflows/lint-md.yml vendored Normal file
View file

@ -0,0 +1,38 @@
name: Markdown Linting
on:
push:
branches-ignore:
- 'dependabot/**'
- 'renovate/**'
paths:
- '.github/workflows/lint-md.yml'
- '.nvmrc'
- '.prettier*'
- '**/*.md'
- '!AUTHORS.md'
- 'package.json'
- 'yarn.lock'
pull_request:
paths:
- '.github/workflows/lint-md.yml'
- '.nvmrc'
- '.prettier*'
- '**/*.md'
- '!AUTHORS.md'
- 'package.json'
- 'yarn.lock'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Prettier
run: yarn lint:md

40
.github/workflows/lint-yml.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: YML Linting
on:
push:
branches-ignore:
- 'dependabot/**'
- 'renovate/**'
paths:
- 'package.json'
- 'yarn.lock'
- '.nvmrc'
- '.prettier*'
- '**/*.yaml'
- '**/*.yml'
- '.github/workflows/lint-yml.yml'
- '!config/locales/*.yml'
pull_request:
paths:
- 'package.json'
- 'yarn.lock'
- '.nvmrc'
- '.prettier*'
- '**/*.yaml'
- '**/*.yml'
- '.github/workflows/lint-yml.yml'
- '!config/locales/*.yml'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Prettier
run: yarn lint:yml

35
.github/workflows/test-image-build.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: Test container image build
on:
pull_request:
paths:
- .github/workflows/build-nightly.yml
- .github/workflows/build-push-pr.yml
- .github/workflows/build-releases.yml
- .github/workflows/test-image-build.yml
- Dockerfile
- streaming/Dockerfile
permissions:
contents: read
jobs:
build-image:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
uses: ./.github/workflows/build-container-image.yml
with:
file_to_build: Dockerfile
platforms: linux/amd64 # Testing only on native platform so it is performant
cache: true
build-image-streaming:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-streaming
cancel-in-progress: true
uses: ./.github/workflows/build-container-image.yml
with:
file_to_build: streaming/Dockerfile
platforms: linux/amd64 # Testing only on native platform so it is performant
cache: true

View file

@ -38,5 +38,5 @@ jobs:
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: JavaScript testing
- name: Jest testing
run: yarn jest --reporters github-actions summary

View file

@ -78,8 +78,23 @@ jobs:
- name: Create database
run: './bin/rails db:create'
- name: Run historical migrations with data population
run: './bin/rails tests:migrations:prepare_database'
- name: Run migrations up to v2.0.0
run: './bin/rails db:migrate VERSION=20171010025614'
- name: Populate database with test data
run: './bin/rails tests:migrations:populate_v2'
- name: Run migrations up to v2.4.0
run: './bin/rails db:migrate VERSION=20180514140000'
- name: Populate database with test data
run: './bin/rails tests:migrations:populate_v2_4'
- name: Run migrations up to v2.4.3
run: './bin/rails db:migrate VERSION=20180707154237'
- name: Populate database with test data
run: './bin/rails tests:migrations:populate_v2_4_3'
- name: Run all remaining migrations
run: './bin/rails db:migrate'

View file

@ -45,7 +45,6 @@ jobs:
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7-alpine
options: >-
@ -78,11 +77,28 @@ jobs:
- name: Create database
run: './bin/rails db:create'
- name: Run historical migrations with data population
run: './bin/rails tests:migrations:prepare_database'
- name: Run migrations up to v2.0.0
run: './bin/rails db:migrate VERSION=20171010025614'
- name: Populate database with test data
run: './bin/rails tests:migrations:populate_v2'
- name: Run pre-deployment migrations up to v2.4.0
run: './bin/rails db:migrate VERSION=20180514140000'
env:
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
- name: Populate database with test data
run: './bin/rails tests:migrations:populate_v2_4'
- name: Run migrations up to v2.4.3
run: './bin/rails db:migrate VERSION=20180707154237'
env:
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
- name: Populate database with test data
run: './bin/rails tests:migrations:populate_v2_4_3'
- name: Run all remaining pre-deployment migrations
run: './bin/rails db:migrate'
env:

View file

@ -28,9 +28,6 @@ jobs:
env:
RAILS_ENV: ${{ matrix.mode }}
BUNDLE_WITH: ${{ matrix.mode }}
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: precompile_placeholder
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: precompile_placeholder
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: precompile_placeholder
OTP_SECRET: precompile_placeholder
SECRET_KEY_BASE: precompile_placeholder
@ -55,7 +52,7 @@ jobs:
run: |
tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs*
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
if: matrix.mode == 'test'
with:
path: |-
@ -109,19 +106,18 @@ jobs:
CAS_ENABLED: true
BUNDLE_WITH: 'pam_authentication test'
GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }}
ES_ENABLED: false
strategy:
fail-fast: false
matrix:
ruby-version:
- '3.0'
- '3.1'
- '3.2'
- '.ruby-version'
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v3
with:
path: './'
name: ${{ github.sha }}
@ -143,11 +139,9 @@ jobs:
- name: Upload coverage reports to Codecov
if: matrix.ruby-version == '.ruby-version'
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v3
with:
files: coverage/lcov/mastodon.lcov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test-e2e:
name: End to End testing
@ -187,22 +181,19 @@ jobs:
DISABLE_SIMPLECOV: true
RAILS_ENV: test
BUNDLE_WITH: test
ES_ENABLED: false
LOCAL_DOMAIN: localhost:3000
LOCAL_HTTPS: false
strategy:
fail-fast: false
matrix:
ruby-version:
- '3.0'
- '3.1'
- '3.2'
- '.ruby-version'
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v3
with:
path: './public'
name: ${{ github.sha }}
@ -219,21 +210,21 @@ jobs:
- name: Load database schema
run: './bin/rails db:create db:schema:load db:seed'
- run: bin/rspec spec/system --tag streaming --tag js
- run: bundle exec rake spec:system
- name: Archive logs
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
if: failure()
with:
name: e2e-logs-${{ matrix.ruby-version }}
path: log/
- name: Archive test screenshots
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
if: failure()
with:
name: e2e-screenshots
path: tmp/capybara/
path: tmp/screenshots/
test-search:
name: Elastic Search integration testing
@ -266,8 +257,8 @@ jobs:
ports:
- 6379:6379
elasticsearch:
image: ${{ contains(matrix.search-image, 'elasticsearch') && matrix.search-image || '' }}
search:
image: ${{ matrix.search-image }}
env:
discovery.type: single-node
xpack.security.enabled: false
@ -279,20 +270,6 @@ jobs:
ports:
- 9200:9200
opensearch:
image: ${{ contains(matrix.search-image, 'opensearch') && matrix.search-image || '' }}
env:
discovery.type: single-node
DISABLE_INSTALL_DEMO_CONFIG: true
DISABLE_SECURITY_PLUGIN: true
options: >-
--health-cmd "curl http://localhost:9200/_cluster/health"
--health-interval 10s
--health-timeout 5s
--health-retries 10
ports:
- 9200:9200
env:
DB_HOST: localhost
DB_USER: postgres
@ -308,21 +285,19 @@ jobs:
fail-fast: false
matrix:
ruby-version:
- '3.0'
- '3.1'
- '3.2'
- '.ruby-version'
search-image:
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13
include:
- ruby-version: '.ruby-version'
search-image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2
- ruby-version: '.ruby-version'
search-image: opensearchproject/opensearch:2
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v3
with:
path: './public'
name: ${{ github.sha }}
@ -342,105 +317,15 @@ jobs:
- run: bin/rspec --tag search
- name: Archive logs
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
if: failure()
with:
name: test-search-logs-${{ matrix.ruby-version }}
path: log/
- name: Archive test screenshots
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
if: failure()
with:
name: test-search-screenshots
path: tmp/capybara/
test-back-and-return:
name: Back to original and return test
runs-on: ubuntu-latest
needs:
- build
services:
postgres:
image: postgres:14-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
env:
DB_HOST: localhost
DB_USER: postgres
DB_PASS: postgres
DISABLE_SIMPLECOV: ${{ matrix.ruby-version != '.ruby-version' }}
RAILS_ENV: test
ALLOW_NOPAM: true
PAM_ENABLED: true
PAM_DEFAULT_SERVICE: pam_test
PAM_CONTROLLED_SERVICE: pam_test_controlled
OIDC_ENABLED: true
OIDC_SCOPE: read
SAML_ENABLED: true
CAS_ENABLED: true
BUNDLE_WITH: 'pam_authentication test'
GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }}
ES_ENABLED: false
BACK_UPSTREAM_FORCE: true
strategy:
fail-fast: false
matrix:
ruby-version:
- '.ruby-version'
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: './'
name: ${{ github.sha }}
- name: Expand archived asset artifacts
run: |
tar xvzf artifacts.tar.gz
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
with:
ruby-version: ${{ matrix.ruby-version}}
additional-system-dependencies: ffmpeg imagemagick libpam-dev
- name: Load database schema
run: './bin/rails db:create db:schema:load db:seed'
- name: Back to upstream schema
run: 'bundle exec rake dangerous:back_upstream'
- name: Return to kmyblue
run: './bin/rails db:migrate'
- run: bin/rspec
- name: Upload coverage reports to Codecov
if: matrix.ruby-version == '.ruby-version'
uses: codecov/codecov-action@v3
with:
files: coverage/lcov/mastodon-back-ret.lcov
path: tmp/screenshots/

7
.gitignore vendored
View file

@ -24,12 +24,10 @@
/public/packs-test
.env
.env.production
.env.development
/node_modules/
/build/
# Ignore elasticsearch config
/.elasticsearch.yml
# Ignore Vagrant files
.vagrant/
@ -71,6 +69,3 @@ yarn-debug.log
# Ignore Docker option files
docker-compose.override.yml
# Ignore dotenv .local files
.env*.local

View file

@ -2,6 +2,7 @@ inherits_from: .haml-lint_todo.yml
exclude:
- 'vendor/**/*'
- lib/templates/haml/scaffold/_form.html.haml
require:
- ./lib/linter/haml_middle_dot.rb
@ -12,6 +13,4 @@ linters:
MiddleDot:
enabled: true
LineLength:
max: 300
ViewLength:
max: 200 # Override default value of 100 inherited from rubocop
max: 320

View file

@ -10,27 +10,4 @@ linters:
# Offense count: 1
LineLength:
exclude:
- 'app/views/admin/ng_rules/_ng_rule_fields.html.haml'
- 'app/views/admin/roles/_form.html.haml'
# Offense count: 9
RuboCop:
exclude:
- 'app/views/home/index.html.haml'
ViewLength:
exclude:
- 'app/views/admin/accounts/index.html.haml'
- 'app/views/admin/instances/show.html.haml'
- 'app/views/admin/ng_rules/_ng_rule_fields.html.haml'
- 'app/views/admin/settings/discovery/show.html.haml'
- 'app/views/settings/preferences/appearance/show.html.haml'
- 'app/views/settings/preferences/other/show.html.haml'
InstanceVariables:
exclude:
- 'app/views/application/_sidebar.html.haml'
- 'app/views/admin/ng_rules/_ng_rule_fields.html.haml'
- 'app/views/admin/ng_words/keywords/_ng_word.html.haml'
- 'app/views/admin/ng_words/white_list/_specified_domain.html.haml'
- 'app/views/admin/sensitive_words/_sensitive_word.html.haml'

View file

@ -1 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint-staged

2
.nvmrc
View file

@ -1 +1 @@
20.13
20.11

View file

@ -54,13 +54,6 @@
# Ignore Docker option files
docker-compose.override.yml
# Ignore public
/public/assets
/public/emoji
/public/packs
/public/packs-test
/public/system
# Ignore emoji map file
/app/javascript/mastodon/features/emoji/emoji_map.json
@ -81,5 +74,4 @@ app/javascript/styles/mastodon/reset.scss
# Ignore the generated AUTHORS.md
AUTHORS.md
# Process a few selected JS files
!lint-staged.config.js

View file

@ -9,13 +9,12 @@ inherit_mode:
require:
- rubocop-rails
- rubocop-rspec
- rubocop-rspec_rails
- rubocop-performance
- rubocop-capybara
- ./lib/linter/rubocop_middle_dot
AllCops:
TargetRubyVersion: 3.1 # Set to minimum supported version of CI
TargetRubyVersion: 3.0 # Set to minimum supported version of CI
DisplayCopNames: true
DisplayStyleGuide: true
ExtraDetails: true
@ -23,7 +22,7 @@ AllCops:
CacheRootDirectory: tmp
NewCops: enable # Opt-in to newly added rules
Exclude:
- 'db/schema.rb'
- db/schema.rb
- 'bin/*'
- 'node_modules/**/*'
- 'Vagrantfile'
@ -40,7 +39,13 @@ Layout/FirstHashElementIndentation:
# Reason: Currently disabled in .rubocop_todo.yml
# https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength
Layout/LineLength:
Max: 300 # Default of 120 causes a duplicate entry in generated todo file
Max: 320 # Default of 120 causes a duplicate entry in generated todo file
# Reason:
# https://docs.rubocop.org/rubocop/cops_lint.html#lintuselessaccessmodifier
Lint/UselessAccessModifier:
ContextCreatingMethods:
- class_methods
## Disable most Metrics/*Length cops
# Reason: those are often triggered and force significant refactors when this happend
@ -68,18 +73,12 @@ Metrics/ModuleLength:
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsabcsize
Metrics/AbcSize:
Exclude:
- 'app/serializers/initial_state_serializer.rb'
- 'lib/mastodon/cli/*.rb'
# Reason: Currently disabled in .rubocop_todo.yml
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricscyclomaticcomplexity
Metrics/CyclomaticComplexity:
Exclude:
- 'app/lib/feed_manager.rb'
- 'app/policies/status_policy.rb'
- 'app/services/activitypub/process_account_service.rb'
- 'app/services/delivery_antenna_service.rb'
- 'app/services/post_status_service.rb'
- lib/mastodon/cli/*.rb
# Reason:
@ -87,17 +86,6 @@ Metrics/CyclomaticComplexity:
Metrics/ParameterLists:
CountKeywordArgs: false
Metrics/PerceivedComplexity:
Exclude:
- 'app/policies/status_policy.rb'
- 'app/services/delivery_antenna_service.rb'
- 'app/services/post_status_service.rb'
# Reason: Prefer seeing a variable name
# https://docs.rubocop.org/rubocop/cops_naming.html#namingblockforwarding
Naming/BlockForwarding:
EnforcedStyle: explicit
# Reason: Prevailing style is argument file paths
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsfilepath
Rails/FilePath:
@ -108,26 +96,22 @@ Rails/FilePath:
Rails/HttpStatus:
EnforcedStyle: numeric
# Reason: Allowed in `tootctl` CLI code and in boot ENV checker
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsexit
Rails/Exit:
Exclude:
- 'config/boot.rb'
- 'lib/mastodon/cli/*.rb'
# Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter
Rails/LexicallyScopedActionFilter:
Exclude:
- 'app/controllers/auth/*'
# Reason: These tasks are doing local work which do not need full env loaded
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsrakeenvironment
Rails/RakeEnvironment:
Exclude:
- 'lib/tasks/auto_annotate_models.rake'
- 'lib/tasks/emojis.rake'
- 'lib/tasks/mastodon.rake'
- 'lib/tasks/repo.rake'
- 'lib/tasks/statistics.rake'
# Reason: There are appropriate times to use these features
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsskipsmodelvalidations
Rails/SkipsModelValidations:
Enabled: false
Exclude:
- 'db/*migrate/**/*'
# Reason: We want to preserve the ability to migrate from arbitrary old versions,
# and cannot guarantee that every installation has run every migration as they upgrade.
@ -140,11 +124,6 @@ Rails/UnusedIgnoredColumns:
Rails/NegateInclude:
Enabled: false
# Reason: Enforce default limit, but allow some elements to span lines
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecexamplelength
RSpec/ExampleLength:
CountAsOne: ['array', 'heredoc', 'method_call']
# Reason: Deprecated cop, will be removed in 3.0, replaced by SpecFilePathFormat
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecfilepath
RSpec/FilePath:
@ -160,6 +139,11 @@ RSpec/NamedSubject:
RSpec/NotToNot:
EnforcedStyle: to_not
# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus
# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus
RSpec/Rails/HttpStatus:
EnforcedStyle: numeric
# Reason: Match overrides from Rspec/FilePath rule above
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecspecfilepathformat
RSpec/SpecFilePathFormat:
@ -170,11 +154,6 @@ RSpec/SpecFilePathFormat:
OEmbedController: oembed_controller
OStatus: ostatus
# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus
# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus
RSpecRails/HttpStatus:
EnforcedStyle: numeric
# Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#styleclassandmodulechildren
Style/ClassAndModuleChildren:
@ -185,25 +164,10 @@ Style/ClassAndModuleChildren:
Style/Documentation:
Enabled: false
# Reason: Route redirects are not token-formatted and must be skipped
# https://docs.rubocop.org/rubocop/cops_style.html#styleformatstringtoken
Style/FormatStringToken:
inherit_mode:
merge:
- AllowedMethods # The rubocop-rails config adds `redirect`
AllowedMethods:
- redirect_with_vary
# Reason: Prevailing style choice
# https://docs.rubocop.org/rubocop/cops_style.html#stylehashaslastarrayitem
Style/HashAsLastArrayItem:
Enabled: false
# Reason: Enforce modern Ruby style
# https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax
Style/HashSyntax:
EnforcedStyle: ruby19_no_mixed_keys
EnforcedShorthandSyntax: either
# Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#stylenumericliterals
@ -223,16 +187,16 @@ Style/PercentLiteralDelimiters:
Style/RedundantBegin:
Enabled: false
# Reason: Prevailing style choice
# https://docs.rubocop.org/rubocop/cops_style.html#styleredundantfetchblock
Style/RedundantFetchBlock:
Enabled: false
# Reason: Overridden to reduce implicit StandardError rescues
# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror
Style/RescueStandardError:
EnforcedStyle: implicit
# Reason: Simplify some spec layouts
# https://docs.rubocop.org/rubocop/cops_style.html#stylesemicolon
Style/Semicolon:
AllowAsExpressionSeparator: true
# Reason: Originally disabled for CodeClimate, and no config consensus has been found
# https://docs.rubocop.org/rubocop/cops_style.html#stylesymbolarray
Style/SymbolArray:

View file

@ -1,11 +1,25 @@
# This configuration was generated by
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
# using RuboCop version 1.63.5.
# using RuboCop version 1.59.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include.
# Include: **/*.gemfile, **/Gemfile, **/gems.rb
Bundler/OrderedGems:
Exclude:
- 'Gemfile'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
# URISchemes: http, https
Layout/LineLength:
Exclude:
- 'app/models/account.rb'
Lint/NonLocalExitFromIterator:
Exclude:
- 'app/helpers/jsonld_helper.rb'
@ -29,27 +43,119 @@ Metrics/PerceivedComplexity:
# Configuration parameters: CountAsOne.
RSpec/ExampleLength:
Max: 18
Max: 22
RSpec/MultipleExpectations:
Max: 7
Max: 8
# Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers:
Max: 17
Exclude:
- 'spec/lib/activitypub/activity/create_spec.rb'
- 'spec/services/delete_account_service_spec.rb'
- 'spec/services/fan_out_on_write_service_spec.rb'
# Configuration parameters: AllowedGroups.
RSpec/NestedGroups:
Max: 6
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasAndBelongsToMany:
Exclude:
- 'app/models/concerns/account/associations.rb'
- 'app/models/status.rb'
- 'app/models/tag.rb'
Rails/OutputSafety:
Exclude:
- 'config/initializers/simple_form.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Include.
# Include: **/Rakefile, **/*.rake
Rails/RakeEnvironment:
Exclude:
- 'lib/tasks/auto_annotate_models.rake'
- 'lib/tasks/db.rake'
- 'lib/tasks/emojis.rake'
- 'lib/tasks/mastodon.rake'
- 'lib/tasks/repo.rake'
- 'lib/tasks/statistics.rake'
# Configuration parameters: ForbiddenMethods, AllowedMethods.
# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all
Rails/SkipsModelValidations:
Exclude:
- 'app/controllers/admin/invites_controller.rb'
- 'app/controllers/concerns/session_tracking_concern.rb'
- 'app/models/concerns/account/merging.rb'
- 'app/models/concerns/expireable.rb'
- 'app/models/status.rb'
- 'app/models/trends/links.rb'
- 'app/models/trends/preview_card_batch.rb'
- 'app/models/trends/preview_card_provider_batch.rb'
- 'app/models/trends/status_batch.rb'
- 'app/models/trends/statuses.rb'
- 'app/models/trends/tag_batch.rb'
- 'app/models/trends/tags.rb'
- 'app/models/user.rb'
- 'app/services/activitypub/process_status_update_service.rb'
- 'app/services/approve_appeal_service.rb'
- 'app/services/block_domain_service.rb'
- 'app/services/delete_account_service.rb'
- 'app/services/process_mentions_service.rb'
- 'app/services/unallow_domain_service.rb'
- 'app/services/unblock_domain_service.rb'
- 'app/services/update_status_service.rb'
- 'app/workers/activitypub/post_upgrade_worker.rb'
- 'app/workers/move_worker.rb'
- 'app/workers/scheduler/ip_cleanup_scheduler.rb'
- 'app/workers/scheduler/scheduled_statuses_scheduler.rb'
- 'lib/mastodon/cli/accounts.rb'
- 'lib/mastodon/cli/maintenance.rb'
- 'spec/lib/activitypub/activity/follow_spec.rb'
- 'spec/services/follow_service_spec.rb'
- 'spec/services/update_account_service_spec.rb'
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/UniqueValidationWithoutIndex:
Exclude:
- 'app/models/account_alias.rb'
- 'app/models/custom_filter_status.rb'
- 'app/models/identity.rb'
- 'app/models/webauthn_credential.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: exists, where
Rails/WhereExists:
Exclude:
- 'app/controllers/activitypub/inboxes_controller.rb'
- 'app/controllers/admin/email_domain_blocks_controller.rb'
- 'app/lib/activitypub/activity/create.rb'
- 'app/lib/delivery_failure_tracker.rb'
- 'app/lib/feed_manager.rb'
- 'app/lib/status_cache_hydrator.rb'
- 'app/lib/suspicious_sign_in_detector.rb'
- 'app/models/concerns/account/interactions.rb'
- 'app/models/featured_tag.rb'
- 'app/models/poll.rb'
- 'app/models/session_activation.rb'
- 'app/models/status.rb'
- 'app/models/user.rb'
- 'app/policies/status_policy.rb'
- 'app/serializers/rest/announcement_serializer.rb'
- 'app/serializers/rest/tag_serializer.rb'
- 'app/services/activitypub/fetch_remote_status_service.rb'
- 'app/services/vote_service.rb'
- 'app/validators/reaction_validator.rb'
- 'app/validators/vote_validator.rb'
- 'app/workers/move_worker.rb'
- 'lib/tasks/tests.rake'
- 'spec/models/account_spec.rb'
- 'spec/services/activitypub/process_collection_service_spec.rb'
- 'spec/services/purge_domain_service_spec.rb'
- 'spec/services/unallow_domain_service_spec.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowedMethods, AllowedPatterns.
# AllowedMethods: ==, equal?, eql?
@ -58,12 +164,17 @@ Style/ClassEqualityComparison:
- 'app/helpers/jsonld_helper.rb'
- 'app/serializers/activitypub/outbox_serializer.rb'
Style/ClassVars:
Exclude:
- 'config/initializers/devise.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowedVars.
Style/FetchEnvVar:
Exclude:
- 'app/lib/redis_configuration.rb'
- 'app/lib/translation_service.rb'
- 'config/environments/development.rb'
- 'config/environments/production.rb'
- 'config/initializers/2_limited_federation_mode.rb'
- 'config/initializers/3_omniauth.rb'
@ -73,8 +184,9 @@ Style/FetchEnvVar:
- 'config/initializers/paperclip.rb'
- 'config/initializers/vapid.rb'
- 'lib/mastodon/redis_config.rb'
- 'lib/premailer_webpack_strategy.rb'
- 'lib/tasks/repo.rake'
- 'spec/system/profile_spec.rb'
- 'spec/features/profile_spec.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns.
@ -82,6 +194,7 @@ Style/FetchEnvVar:
# AllowedMethods: redirect
Style/FormatStringToken:
Exclude:
- 'app/models/privacy_policy.rb'
- 'config/initializers/devise.rb'
- 'lib/paperclip/color_extractor.rb'
@ -95,6 +208,10 @@ Style/GlobalStdStream:
# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals.
Style/GuardClause:
Exclude:
- 'app/controllers/admin/confirmations_controller.rb'
- 'app/controllers/auth/confirmations_controller.rb'
- 'app/controllers/auth/passwords_controller.rb'
- 'app/controllers/settings/two_factor_authentication/webauthn_credentials_controller.rb'
- 'app/lib/activitypub/activity/block.rb'
- 'app/lib/request.rb'
- 'app/lib/request_pool.rb'
@ -118,14 +235,35 @@ Style/GuardClause:
- 'lib/mastodon/cli/accounts.rb'
- 'lib/mastodon/cli/maintenance.rb'
- 'lib/mastodon/cli/media.rb'
- 'lib/paperclip/attachment_extensions.rb'
- 'lib/tasks/repo.rake'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: braces, no_braces
Style/HashAsLastArrayItem:
Exclude:
- 'app/controllers/admin/statuses_controller.rb'
- 'app/controllers/api/v1/statuses_controller.rb'
- 'app/models/concerns/account/counters.rb'
- 'app/models/concerns/status/threading_concern.rb'
- 'app/models/status.rb'
- 'app/services/batched_remove_status_service.rb'
- 'app/services/notify_service.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/HashTransformValues:
Exclude:
- 'app/serializers/rest/web_push_subscription_serializer.rb'
- 'app/services/import_service.rb'
# This cop supports safe autocorrection (--autocorrect).
Style/IfUnlessModifier:
Exclude:
- 'config/environments/production.rb'
- 'config/initializers/devise.rb'
- 'config/initializers/ffmpeg.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/MapToHash:
Exclude:
@ -160,6 +298,13 @@ Style/OptionalBooleanParameter:
- 'app/workers/unfollow_follow_worker.rb'
- 'lib/mastodon/redis_config.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
Exclude:
- 'config/deploy.rb'
- 'config/initializers/doorkeeper.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: short, verbose
@ -173,6 +318,16 @@ Style/RedundantConstantBase:
- 'config/environments/production.rb'
- 'config/initializers/sidekiq.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: SafeForConstants.
Style/RedundantFetchBlock:
Exclude:
- 'config/initializers/1_hosts.rb'
- 'config/initializers/chewy.rb'
- 'config/initializers/devise.rb'
- 'config/initializers/paperclip.rb'
- 'config/puma.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength.
# AllowedMethods: present?, blank?, presence, try, try!
@ -180,12 +335,59 @@ Style/SafeNavigation:
Exclude:
- 'app/models/concerns/account/finder_concern.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: only_raise, only_fail, semantic
Style/SignalException:
Exclude:
- 'lib/devise/strategies/two_factor_ldap_authenticatable.rb'
- 'lib/devise/strategies/two_factor_pam_authenticatable.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/SingleArgumentDig:
Exclude:
- 'lib/webpacker/manifest_extensions.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Mode.
Style/StringConcatenation:
Exclude:
- 'config/initializers/paperclip.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiterals:
Exclude:
- 'config/environments/production.rb'
- 'config/initializers/backtrace_silencers.rb'
- 'config/initializers/http_client_proxy.rb'
- 'config/initializers/rack_attack.rb'
- 'config/initializers/webauthn.rb'
- 'config/routes.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, AllowSafeAssignment.
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
Style/TernaryParentheses:
Exclude:
- 'config/environments/development.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArguments:
Exclude:
- 'config/initializers/paperclip.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInHashLiteral:
Exclude:
- 'config/environments/production.rb'
- 'config/environments/test.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: WordRegex.
# SupportedStyles: percent, brackets

View file

@ -1 +1 @@
3.3.1
3.2.2

22
.simplecov Normal file
View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
if ENV['CI']
require 'simplecov-lcov'
SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
else
SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter
end
SimpleCov.start 'rails' do
enable_coverage :branch
add_filter 'lib/linter'
add_group 'Libraries', 'lib'
add_group 'Policies', 'app/policies'
add_group 'Presenters', 'app/presenters'
add_group 'Serializers', 'app/serializers'
add_group 'Services', 'app/services'
add_group 'Validators', 'app/validators'
end

View file

@ -1,18 +0,0 @@
# Authors for kmyblue fork
## 貢献者
kmyblueフォークは、以下の方の貢献によって成り立っています。
本家Mastodonの貢献者については、`AUTHORS.md`をご覧ください。
- [aoisensi](https://github.com/aoisensi)
- [KMY](https://github.com/kmycode)
- [S-H-GAMELINKS](https://github.com/S-H-GAMELINKS)
- [Yuicho](https://github.com/yuicho)
## 特記
kmyblueフォークの開発にあたって、API・Activity仕様の設計一部機能については内部仕様策定の過程で下記リポジトリのコードを参考にしました。
kmyblueフォークに直接貢献したわけではありませんが、以下のリポジトリにある絵文字リアクション機能・検索範囲機能のコードのうち一部にkmyblueへ転写した箇所がございますため、お名前記載させていただきます。
- [Fedibird](https://github.com/fedibird/mastodon)

View file

@ -2,101 +2,6 @@
All notable changes to this project will be documented in this file.
## [4.2.7] - 2024-02-16
### Fixed
- Fix OmniAuth tests and edge cases in error handling ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29201), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/29207))
- Fix new installs by upgrading to the latest release of the `nsa` gem, instead of a no longer existing commit ([mjankowski](https://github.com/mastodon/mastodon/pull/29065))
### Security
- Fix insufficient checking of remote posts ([GHSA-jhrq-qvrm-qr36](https://github.com/mastodon/mastodon/security/advisories/GHSA-jhrq-qvrm-qr36))
## [4.2.6] - 2024-02-14
### Security
- Update the `sidekiq-unique-jobs` dependency (see [GHSA-cmh9-rx85-xj38](https://github.com/mhenrixon/sidekiq-unique-jobs/security/advisories/GHSA-cmh9-rx85-xj38))
In addition, we have disabled the web interface for `sidekiq-unique-jobs` out of caution.
If you need it, you can re-enable it by setting `ENABLE_SIDEKIQ_UNIQUE_JOBS_UI=true`.
If you only need to clear all locks, you can now use `bundle exec rake sidekiq_unique_jobs:delete_all_locks`.
- Update the `nokogiri` dependency (see [GHSA-xc9x-jj77-9p9j](https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-xc9x-jj77-9p9j))
- Disable administrative Doorkeeper routes ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/29187))
- Fix ongoing streaming sessions not being invalidated when applications get deleted in some cases ([GHSA-7w3c-p9j8-mq3x](https://github.com/mastodon/mastodon/security/advisories/GHSA-7w3c-p9j8-mq3x))
In some rare cases, the streaming server was not notified of access tokens revocation on application deletion.
- Change external authentication behavior to never reattach a new identity to an existing user by default ([GHSA-vm39-j3vx-pch3](https://github.com/mastodon/mastodon/security/advisories/GHSA-vm39-j3vx-pch3))
Up until now, Mastodon has allowed new identities from external authentication providers to attach to an existing local user based on their verified e-mail address.
This allowed upgrading users from a database-stored password to an external authentication provider, or move from one authentication provider to another.
However, this behavior may be unexpected, and means that when multiple authentication providers are configured, the overall security would be that of the least secure authentication provider.
For these reasons, this behavior is now locked under the `ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH` environment variable.
In addition, regardless of this environment variable, Mastodon will refuse to attach two identities from the same authentication provider to the same account.
## [4.2.5] - 2024-02-01
### Security
- Fix insufficient origin validation (CVE-2024-23832, [GHSA-3fjr-858r-92rw](https://github.com/mastodon/mastodon/security/advisories/GHSA-3fjr-858r-92rw))
## [4.2.4] - 2024-01-24
### Fixed
- Fix error when processing remote files with unusually long names ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28823))
- Fix processing of compacted single-item JSON-LD collections ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28816))
- Retry 401 errors on replies fetching ([ShadowJonathan](https://github.com/mastodon/mastodon/pull/28788))
- Fix `RecordNotUnique` errors in LinkCrawlWorker ([tribela](https://github.com/mastodon/mastodon/pull/28748))
- Fix Mastodon not correctly processing HTTP Signatures with query strings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28443), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/28476))
- Fix potential redirection loop of streaming endpoint ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28665))
- Fix streaming API redirection ignoring the port of `streaming_api_base_url` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28558))
- Fix error when processing link preview with an array as `inLanguage` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28252))
- Fix unsupported time zone or locale preventing sign-up ([Gargron](https://github.com/mastodon/mastodon/pull/28035))
- Fix "Hide these posts from home" list setting not refreshing when switching lists ([brianholley](https://github.com/mastodon/mastodon/pull/27763))
- Fix missing background behind dismissable banner in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/27479))
- Fix line wrapping of language selection button with long locale codes ([gunchleoc](https://github.com/mastodon/mastodon/pull/27100), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27127))
- Fix `Undo Announce` activity not being sent to non-follower authors ([MitarashiDango](https://github.com/mastodon/mastodon/pull/18482))
- Fix N+1s because of association preloaders not actually getting called ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28339))
- Fix empty column explainer getting cropped under certain conditions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28337))
- Fix `LinkCrawlWorker` error when encountering empty OEmbed response ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28268))
- Fix call to inefficient `delete_matched` cache method in domain blocks ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28367))
### Security
- Add rate-limit of TOTP authentication attempts at controller level ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28801))
## [4.2.3] - 2023-12-05
### Fixed
- Fix dependency on `json-canonicalization` version that has been made unavailable since last release
## [4.2.2] - 2023-12-04
### Changed
- Change dismissed banners to be stored server-side ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27055))
- Change GIF max matrix size error to explicitly mention GIF files ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27927))
- Change `Follow` activities delivery to bypass availability check ([ShadowJonathan](https://github.com/mastodon/mastodon/pull/27586))
- Change single-column navigation notice to be displayed outside of the logo container ([renchap](https://github.com/mastodon/mastodon/pull/27462), [renchap](https://github.com/mastodon/mastodon/pull/27476))
- Change Content-Security-Policy to be tighter on media paths ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26889))
- Change post language code to include country code when relevant ([gunchleoc](https://github.com/mastodon/mastodon/pull/27099), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27207))
### Fixed
- Fix upper border radius of onboarding columns ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27890))
- Fix incoming status creation date not being restricted to standard ISO8601 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27655), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/28081))
- Fix some posts from threads received out-of-order sometimes not being inserted into timelines ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27653))
- Fix posts from force-sensitized accounts being able to trend ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27620))
- Fix error when trying to delete already-deleted file with OpenStack Swift ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27569))
- Fix batch attachment deletion when using OpenStack Swift ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27554))
- Fix processing LDSigned activities from actors with unknown public keys ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27474))
- Fix error and incorrect URLs in `/api/v1/accounts/:id/featured_tags` for remote accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27459))
- Fix report processing notice not mentioning the report number when performing a custom action ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27442))
- Fix handling of `inLanguage` attribute in preview card processing ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27423))
- Fix own posts being removed from home timeline when unfollowing a used hashtag ([kmycode](https://github.com/mastodon/mastodon/pull/27391))
- Fix some link anchors being recognized as hashtags ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27271), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27584))
- Fix format-dependent redirects being cached regardless of requested format ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27634))
## [4.2.1] - 2023-10-10
### Added

View file

@ -1,35 +1,50 @@
# CONTRIBUTING
# Contributing
kmyblueは、コミュニティの意見も聞くには聞きますが導入する・しないは管理人が決定します。
Thank you for considering contributing to Mastodon 🐘
## バグ報告
You can contribute in the following ways:
バグについて、L最新よりも過去のバージョンへの対応は、LTSや特別な場合以外は行いません。
- Finding and reporting bugs
- Translating the Mastodon interface into various languages
- Contributing code to Mastodon by fixing bugs or implementing features
- Improving the documentation
以下のいずれかの方法で報告してください。
If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon).
- [GitHub Issues](https://github.com/kmycode/mastodon/issues) (セキュリティインシデントはここの一番下から)
- [kmyblue開発者への連絡](https://kmy.blue/@askyq)
- [kmyblue開発者へのメール](https://kmy.blue/about)
## API Changes and Additions
## 翻訳、プルリクエスト
Please note that any changes or additions made to the API should have an accompanying pull request on [our documentation repository](https://github.com/mastodon/documentation).
新しい機能や既存機能の修正については、プルリクエストのためにコードを作成する前に、まずGitHub Issuesで機能の提案を行いkmyblue開発者の考えを聞くことをおすすめします。バグ修正、翻訳、テストコードなどは基本受け入れますが、依存モジュールのバージョンアップについては特別な事情がなければ本家Mastodonよりも先に行かないようにしてください。
## Bug reports
プルリクエストのタイトルには、プルリクエストの内容が明確になるようなものを設定してください。
Bug reports and feature suggestions must use descriptive and concise titles and be submitted to [GitHub Issues](https://github.com/mastodon/mastodon/issues). Please use the search function to make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected.
### kmyblueの開発方針
## Translations
下記のものに矛盾がなければ、あとは管理人の意向次第です。
You can submit translations via [Crowdin](https://crowdin.com/project/mastodon). They are periodically merged into the codebase.
- **自分の投稿を見せたくない人に見せない**
- **他人の見たくない投稿を見ない**
- ただし本家Mastodonで上記原則に矛盾した機能が追加された場合は従う
- 画面を騒がしくするような機能(絵文字を大きく表示するなど)は追加しないか、控えめにする。ただし他のソフトウェアにも導入され利用者が多くいる場合などは別途判断して、オプトアウト可能な設定項目とともに追加する
- 負荷を著しく上げるような機能はできるだけ追加しない
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)](https://crowdin.com/project/mastodon)
kmyblueが意図的に実装していない機能は、例えば以下のものがあります。詳しい理由が知りたい場合は[この記事を参照するか](https://note.com/kmycode/n/n463410b5e03c)、別途お問い合わせください。もちろん明確な根拠がある場合、あなたはこれに抗議する権利を有しますが、あなたがこのkmyblueをフォークして新しいリポジトリを作るほうがより自由でしょう。
## Pull requests
- お気に入り一覧の公開
- ブックマーク分類の公開
- Fedibird、Misskeyにあるような詳細な画面表示オプション
**Please use clean, concise titles for your pull requests.** Unless the pull request is about refactoring code, updating dependencies or other internal tasks, assume that the person reading the pull request title is not a programmer or Mastodon developer, but instead a Mastodon user or server administrator, and **try to describe your change or fix from their perspective**. We use commit squashing, so the final commit in the main branch will carry the title of the pull request, and commits from the main branch are fed into the changelog. The changelog is separated into [keepachangelog.com categories](https://keepachangelog.com/en/1.0.0/), and while that spec does not prescribe how the entries ought to be named, for easier sorting, start your pull request titles using one of the verbs "Add", "Change", "Deprecate", "Remove", or "Fix" (present tense).
Example:
| Not ideal | Better |
| ------------------------------------ | ------------------------------------------------------------- |
| Fixed NoMethodError in RemovalWorker | Fix nil error when removing statuses caused by race condition |
It is not always possible to phrase every change in such a manner, but it is desired.
**The smaller the set of changes in the pull request is, the quicker it can be reviewed and merged.** Splitting tasks into multiple smaller pull requests is often preferable.
**Pull requests that do not pass automated checks may not be reviewed**. In particular, you need to keep in mind:
- Unit and integration tests (rspec, jest)
- Code style rules (rubocop, eslint)
- Normalization of locale files (i18n-tasks)
## Documentation
The [Mastodon documentation](https://docs.joinmastodon.org) is a statically generated site. You can [submit merge requests to mastodon/documentation](https://github.com/mastodon/documentation).

View file

@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.7
# syntax=docker/dockerfile:1.4
# Please see https://docs.docker.com/engine/reference/builder for information about
# the extended buildx capabilities used in this file.
@ -7,20 +7,20 @@
ARG TARGETPLATFORM=${TARGETPLATFORM}
ARG BUILDPLATFORM=${BUILDPLATFORM}
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.1"]
ARG RUBY_VERSION="3.3.1"
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.2"]
ARG RUBY_VERSION="3.2.2"
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
ARG NODE_MAJOR_VERSION="20"
# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"]
ARG DEBIAN_VERSION="bookworm"
# Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node
# Ruby image to use for base image based on combined variables (ex: 3.3.1-slim-bookworm)
# Ruby image to use for base image based on combined variables (ex: 3.2.2-slim-bookworm)
FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
# Example: v4.2.0-nightly.2023.11.09+something
# Overwrite existence of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"]
# Overwrite existance of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"]
ARG MASTODON_VERSION_PRERELEASE=""
# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"]
ARG MASTODON_VERSION_METADATA=""
@ -29,7 +29,7 @@ ARG MASTODON_VERSION_METADATA=""
# See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
ARG RAILS_SERVE_STATIC_FILES="true"
# Allow to use YJIT compiler
# See: https://github.com/ruby/ruby/blob/v3_2_4/doc/yjit/yjit.md
# See: https://github.com/ruby/ruby/blob/master/doc/yjit/yjit.md
ARG RUBY_YJIT_ENABLE="1"
# Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin]
ARG TZ="Etc/UTC"
@ -205,12 +205,7 @@ ARG TARGETPLATFORM
RUN \
# Use Ruby on Rails to create Mastodon assets
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=precompile_placeholder \
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=precompile_placeholder \
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=precompile_placeholder \
OTP_SECRET=precompile_placeholder \
SECRET_KEY_BASE=precompile_placeholder \
bundle exec rails assets:precompile; \
OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile; \
# Cleanup temporary files
rm -fr /opt/mastodon/tmp;
@ -262,4 +257,4 @@ USER mastodon
# Expose default Puma ports
EXPOSE 3000
# Set container tini as default entry point
ENTRYPOINT ["/usr/bin/tini", "--"]
ENTRYPOINT ["/usr/bin/tini", "--"]

View file

@ -1,35 +1,19 @@
# Federation
## Supported federation protocols and standards
- [ActivityPub](https://www.w3.org/TR/activitypub/) (Server-to-Server)
- [WebFinger](https://webfinger.net/)
- [Http Signatures](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures)
- [NodeInfo](https://nodeinfo.diaspora.software/)
## Supported FEPs
- [FEP-67ff: FEDERATION.md](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md)
- [FEP-f1d5: NodeInfo in Fediverse Software](https://codeberg.org/fediverse/fep/src/branch/main/fep/f1d5/fep-f1d5.md)
- [FEP-8fcf: Followers collection synchronization across servers](https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md)
- [FEP-5feb: Search indexing consent for actors](https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md)
## ActivityPub in Mastodon
## ActivityPub federation in Mastodon
Mastodon largely follows the ActivityPub server-to-server specification but it makes uses of some non-standard extensions, some of which are required for interacting with Mastodon at all.
- [Supported ActivityPub vocabulary](https://docs.joinmastodon.org/spec/activitypub/)
Supported vocabulary: https://docs.joinmastodon.org/spec/activitypub/
### Required extensions
#### WebFinger
#### Webfinger
In Mastodon, users are identified by a `username` and `domain` pair (e.g., `Gargron@mastodon.social`).
This is used both for discovery and for unambiguously mentioning users across the fediverse. Furthermore, this is part of Mastodon's database design from its very beginnings.
As a result, Mastodon requires that each ActivityPub actor uniquely maps back to an `acct:` URI that can be resolved via WebFinger.
- [WebFinger information and examples](https://docs.joinmastodon.org/spec/webfinger/)
More information and examples are available at: https://docs.joinmastodon.org/spec/webfinger/
#### HTTP Signatures
@ -37,13 +21,11 @@ In order to authenticate activities, Mastodon relies on HTTP Signatures, signing
Mastodon requires all `POST` requests to be signed, and MAY require `GET` requests to be signed, depending on the configuration of the Mastodon server.
- [HTTP Signatures information and examples](https://docs.joinmastodon.org/spec/security/#http)
More information on HTTP Signatures, as well as examples, can be found here: https://docs.joinmastodon.org/spec/security/#http
### Optional extensions
- [Linked-Data Signatures](https://docs.joinmastodon.org/spec/security/#ld)
- [Bearcaps](https://docs.joinmastodon.org/spec/bearcaps/)
### Additional documentation
- [Mastodon documentation](https://docs.joinmastodon.org/)
- Linked-Data Signatures: https://docs.joinmastodon.org/spec/security/#ld
- Bearcaps: https://docs.joinmastodon.org/spec/bearcaps/
- Followers collection synchronization: https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md
- Search indexing consent for actors: https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md

85
Gemfile
View file

@ -1,37 +1,37 @@
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '>= 3.1.0'
ruby '>= 3.0.0'
gem 'propshaft'
gem 'puma', '~> 6.3'
gem 'rack', '~> 2.2.7'
gem 'rails', '~> 7.1.1'
gem 'propshaft'
gem 'thor', '~> 1.2'
gem 'rack', '~> 2.2.7'
# For why irb is in the Gemfile, see: https://ruby.social/@st0012/111444685161478182
gem 'irb', '~> 1.8'
gem 'dotenv'
gem 'haml-rails', '~>2.0'
gem 'pg', '~> 1.5'
gem 'pghero'
gem 'dotenv-rails', '~> 2.8'
gem 'aws-sdk-s3', '~> 1.123', require: false
gem 'blurhash', '~> 0.1'
gem 'fog-core', '<= 2.4.0'
gem 'fog-openstack', '~> 1.0', require: false
gem 'kt-paperclip', '~> 7.2'
gem 'md-paperclip-azure', '~> 2.2', require: false
gem 'blurhash', '~> 0.1'
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.8'
gem 'bootsnap', '~> 1.18.0', require: false
gem 'bootsnap', '~> 1.17.0', require: false
gem 'browser'
gem 'charlock_holmes', '~> 0.7.7'
gem 'chewy', '~> 7.3'
gem 'devise', '~> 4.9'
gem 'devise-two-factor'
gem 'devise-two-factor', '~> 4.1'
group :pam_authentication, optional: true do
gem 'devise_pam_authenticatable2', '~> 9.2'
@ -39,11 +39,11 @@ end
gem 'net-ldap', '~> 0.18'
gem 'omniauth', '~> 2.0'
gem 'omniauth-cas', '~> 3.0.0.beta.1'
gem 'omniauth_openid_connect', '~> 0.6.1'
gem 'omniauth-rails_csrf_protection', '~> 1.0'
gem 'omniauth-saml', '~> 2.0'
gem 'omniauth_openid_connect', '~> 0.6.1'
gem 'omniauth', '~> 2.0'
gem 'omniauth-rails_csrf_protection', '~> 1.0'
gem 'color_diff', '~> 0.1'
gem 'csv', '~> 3.2'
@ -53,49 +53,48 @@ gem 'ed25519', '~> 1.3'
gem 'fast_blank', '~> 1.0'
gem 'fastimage'
gem 'hiredis', '~> 0.6'
gem 'redis-namespace', '~> 1.10'
gem 'htmlentities', '~> 4.3'
gem 'http', '~> 5.2.0'
gem 'http', '~> 5.1'
gem 'http_accept_language', '~> 2.1'
gem 'httplog', '~> 1.6.2'
gem 'i18n'
gem 'idn-ruby', require: 'idn'
gem 'inline_svg'
gem 'kaminari', '~> 1.2'
gem 'link_header', '~> 0.0'
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
gem 'nokogiri', '~> 1.15'
gem 'nsa'
gem 'nsa', github: 'jhawthorn/nsa', ref: 'e020fcc3a54d993ab45b7194d89ab720296c111b'
gem 'oj', '~> 3.14'
gem 'ox', '~> 2.14'
gem 'parslet'
gem 'premailer-rails'
gem 'posix-spawn'
gem 'public_suffix', '~> 5.0'
gem 'pundit', '~> 2.3'
gem 'premailer-rails'
gem 'rack-attack', '~> 6.6'
gem 'rack-cors', '~> 2.0', require: 'rack/cors'
gem 'rails-i18n', '~> 7.0'
gem 'redcarpet', '~> 3.6'
gem 'redis', '~> 4.5', require: ['redis', 'redis/connection/hiredis']
gem 'redis-namespace', '~> 1.10'
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 2.2'
gem 'ruby-progressbar', '~> 1.13'
gem 'sanitize', '~> 6.0'
gem 'scenic', '~> 1.7'
gem 'sidekiq', '~> 6.5'
gem 'sidekiq-bulk', '~> 0.2.0'
gem 'sidekiq-scheduler', '~> 5.0'
gem 'sidekiq-unique-jobs', '~> 7.1'
gem 'simple_form', '~> 5.2'
gem 'sidekiq-bulk', '~> 0.2.0'
gem 'simple-navigation', '~> 4.4'
gem 'stoplight', '~> 4.1'
gem 'strong_migrations', '1.8.0'
gem 'simple_form', '~> 5.2'
gem 'stoplight', '~> 3.0.1'
gem 'strong_migrations', '1.7.0'
gem 'tty-prompt', '~> 0.23', require: false
gem 'twitter-text', '~> 3.1.0'
gem 'tzinfo-data', '~> 1.2023'
gem 'webauthn', '~> 3.0'
gem 'webpacker', '~> 5.4'
gem 'webpush', github: 'ClearlyClaire/webpush', ref: 'f14a4d52e201128b1b00245d11b6de80d6cfdcd9'
gem 'webauthn', '~> 3.0'
gem 'json-ld'
gem 'json-ld-preloaded', '~> 3.2'
@ -103,24 +102,6 @@ gem 'rdf-normalize', '~> 0.5'
gem 'private_address_check', '~> 0.5'
group :opentelemetry do
gem 'opentelemetry-exporter-otlp', '~> 0.26.3', require: false
gem 'opentelemetry-instrumentation-active_job', '~> 0.7.1', require: false
gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.20.1', require: false
gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.21.2', require: false
gem 'opentelemetry-instrumentation-excon', '~> 0.22.0', require: false
gem 'opentelemetry-instrumentation-faraday', '~> 0.24.1', require: false
gem 'opentelemetry-instrumentation-http', '~> 0.23.2', require: false
gem 'opentelemetry-instrumentation-http_client', '~> 0.22.3', require: false
gem 'opentelemetry-instrumentation-net_http', '~> 0.22.4', require: false
gem 'opentelemetry-instrumentation-pg', '~> 0.27.1', require: false
gem 'opentelemetry-instrumentation-rack', '~> 0.24.1', require: false
gem 'opentelemetry-instrumentation-rails', '~> 0.30.0', require: false
gem 'opentelemetry-instrumentation-redis', '~> 0.25.3', require: false
gem 'opentelemetry-instrumentation-sidekiq', '~> 0.25.2', require: false
gem 'opentelemetry-sdk', '~> 1.4', require: false
end
group :test do
# Adds RSpec Error/Warning annotations to GitHub PRs on the Files tab
gem 'rspec-github', '~> 2.4', require: false
@ -131,8 +112,8 @@ group :test do
# RSpec helpers for email specs
gem 'email_spec'
# Extra RSpec extension methods and helpers for sidekiq
gem 'rspec-sidekiq', '~> 5.0'
# Extra RSpec extenion methods and helpers for sidekiq
gem 'rspec-sidekiq', '~> 4.0'
# Browser integration testing
gem 'capybara', '~> 3.39'
@ -142,7 +123,13 @@ group :test do
gem 'database_cleaner-active_record'
# Used to mock environment variables
gem 'climate_control'
gem 'climate_control', '~> 0.2'
# Generating fake data for specs
gem 'faker', '~> 3.2'
# Generate test objects for specs
gem 'fabrication', '~> 2.30'
# Add back helpers functions removed in Rails 5.1
gem 'rails-controller-testing', '~> 1.0'
@ -178,7 +165,7 @@ group :development do
# Preview mail in the browser
gem 'letter_opener', '~> 1.8'
gem 'letter_opener_web', '~> 3.0'
gem 'letter_opener_web', '~> 2.0'
# Security analysis CLI tools
gem 'brakeman', '~> 6.0', require: false
@ -195,12 +182,6 @@ group :development, :test do
# Interactive Debugging tools
gem 'debug', '~> 1.8'
# Generate fake data values
gem 'faker', '~> 3.2'
# Generate factory objects
gem 'fabrication', '~> 2.30'
# Profiling tools
gem 'memory_profiler', require: false
gem 'ruby-prof', require: false
@ -215,14 +196,12 @@ group :production do
gem 'lograge', '~> 0.12'
end
gem 'cocoon', '~> 1.2'
gem 'concurrent-ruby', require: false
gem 'connection_pool', require: false
gem 'xorcist', '~> 1.1'
gem 'cocoon', '~> 1.2'
gem 'net-http', '~> 0.4.0'
gem 'rubyzip', '~> 2.3'
gem 'hcaptcha', '~> 7.1'
gem 'mail', '~> 2.8'

File diff suppressed because it is too large Load diff

164
README.md
View file

@ -1,112 +1,142 @@
# ![kmyblue icon](https://raw.githubusercontent.com/kmycode/mastodon/kb_development/app/javascript/icons/favicon-32x32.png) kmyblue
<h1><picture>
<source media="(prefers-color-scheme: dark)" srcset="./lib/assets/wordmark.dark.png?raw=true">
<source media="(prefers-color-scheme: light)" srcset="./lib/assets/wordmark.light.png?raw=true">
<img alt="Mastodon" src="./lib/assets/wordmark.light.png?raw=true" height="34">
</picture></h1>
[![Ruby Testing](https://github.com/kmycode/mastodon/actions/workflows/test-ruby.yml/badge.svg)](https://github.com/kmycode/mastodon/actions/workflows/test-ruby.yml)
[![GitHub release](https://img.shields.io/github/release/mastodon/mastodon.svg)][releases]
[![Ruby Testing](https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml/badge.svg)](https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)][crowdin]
kmyblueは[Mastodon](https://github.com/mastodon/mastodon)のフォークです。創作作家のためのMastodonを目指して開発しました。
[releases]: https://github.com/mastodon/mastodon/releases
[crowdin]: https://crowdin.com/project/mastodon
kmyblueはフォーク名であり、同時に[サーバー名](https://kmy.blue)でもあります。以下は特に記述がない限り、フォークとしてのkmyblueをさします。
Mastodon is a **free, open-source social network server** based on ActivityPub where users can follow friends and discover new ones. On Mastodon, users can publish anything they want: links, pictures, text, and video. All Mastodon servers are interoperable as a federated network (users on one server can seamlessly communicate with users from another one, including non-Mastodon software that implements ActivityPub!)
kmyblueは AGPL ライセンスで公開されているため、どなたでも自由にフォークし、このソースコードを元に自分でサーバーを立てて公開することができます。確かにサーバーkmyblueは創作作家向けのものですが、フォークとしてのkmyblueはAGPLでライセンスつけられており、ルールは全くの別物です。創作活動の一部エロ関係含むまたは全体を否定するコミュニティなどにも平等にお使いいただけます。サーバーkmyblueのルールを適用する必要もなく、「Anyone But Kmyblue」なルールを設定することすら許容されます。
kmyblueは、特に非収載投稿の検索が強化されているため、ローカルタイムラインに掲載されていない投稿も検索・購読することが可能な場合があります。閉鎖的なコミュニティ、あまり目立ちたくないコミュニティには特に強力な機能を提供します。それ以外のコミュニティに対しても、kmyblueはプライバシーを考慮したうえで強力な検索・購読機能を提供するため、汎用サーバーとして利用するにもある程度十分な機能が揃っています。
Click below to **learn more** in a video:
ただしkmyblueにおいて**テストコードは飾り**でしかありません。これはkmyblueを利用する人が本家Mastodonより圧倒的に少なく、バグやセキュリティインシデントを発見するだけの人数が足りないことを意味します。kmyblueは対策として自動テストを拡充しています。独自機能のテストを記述するだけでなく、本家のテストコードの補強も行っておりますが、確認漏れは必ず発生するものです。不具合が発生しても自己責任になります。既知のバグもいくつかありますし、直す予定のないものも含まれます。
[![Screenshot](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/ezgif-2-60f1b00403.gif)][youtube_demo]
テストコード、Lint どちらも動いています。
[youtube_demo]: https://www.youtube.com/watch?v=IPSbNdBmWKE
## インストール方法
## Navigation
[Wiki](https://github.com/kmycode/mastodon/wiki/Installation)を参照してください。
- [Project homepage 🐘](https://joinmastodon.org)
- [Support the development via Patreon][patreon]
- [View sponsors](https://joinmastodon.org/sponsors)
- [Blog](https://blog.joinmastodon.org)
- [Documentation](https://docs.joinmastodon.org)
- [Roadmap](https://joinmastodon.org/roadmap)
- [Official Docker image](https://github.com/mastodon/mastodon/pkgs/container/mastodon)
- [Browse Mastodon servers](https://joinmastodon.org/communities)
- [Browse Mastodon apps](https://joinmastodon.org/apps)
## 開発への参加方法
[patreon]: https://www.patreon.com/mastodon
CONTRIBUTING.mdを参照してください。
## Features
## テスト
<img src="/app/javascript/images/elephant_ui_working.svg?raw=true" align="right" width="30%" />
```
# デバッグ実行(以下のいずれか)
foreman start
DB_USER=postgres DB_PASS=password foreman start
### No vendor lock-in: Fully interoperable with any conforming platform
# 一部を除く全てのテストを行う
RAILS_ENV=test bundle exec rspec spec
It doesn't have to be Mastodon; whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/)
# ElasticSearch連携テストを行う
RAILS_ENV=test ES_ENABLED=true bundle exec rspec --tag search
RAILS_ENV=test ES_ENABLED=true RUN_SEARCH_SPECS=true bundle exec rspec spec/search
```
### Real-time, chronological timeline updates
## kmyblueのブランチ
Updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well!
- **main** - 管理者が本家MastodonにPRするときに使うことがあります
- **kb_development** - 開発中の最新のソースコードです。メジャーバージョンアップデートは通常このブランチから公開されます
- **kb_lts** - LTSの管理に使います。LTSはこのブランチから公開されます
- **kb_patch** - 修正パッチの管理に使います。マイナーバージョンアップデートは通常このブランチから公開されます
### Media attachments like images and short videos
## kmyblueの強み
Upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos loop continuously!
追加の詳細は下記記事もご覧ください。
### Safety and moderation tools
https://note.com/kmycode/n/n5fd5e823ed40
Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/)
以下に書いているもの以外にも多数の機能が存在します。
### OAuth2 and a straightforward REST API
### 本家Mastodonへの積極的追従
Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Streaming APIs. This results in a rich app ecosystem with a lot of choices!
kmyblueは、追加機能を控えめにする代わりに本家Mastodonに積極的に追従を行います。kmyblueの追加機能そのままに、Mastodonの新機能も利用できるよう調整を行います。
## Deployment
### ゆるやかな内輪での運用
### Tech stack
kmyblueは同人向けサーバーとして出発したため、同人作家に需要のある「内輪リを外部にできるだけもらさない」という部分に特化しています。
- **Ruby on Rails** powers the REST API and other web pages
- **React.js** and Redux are used for the dynamic parts of the interface
- **Node.js** powers the streaming API
「ローカル公開」という機能によって、「ローカルタイムラインに流すが他のサーバーの連合タイムラインに流さない」投稿が可能です。ただしMisskeyのローカル限定とは異なり、他のサーバーのフォロワーのタイムラインにも投稿は流れます。自分のサーバーの中で内輪で盛り上がって、他のサーバーの連合タイムラインには外面だけの投稿を流すことも可能です。
### Requirements
「サークル」という機能によって、特定のフォロワーにだけ見える投稿を行うことも可能です。その投稿に返信することで、相手サークルの会話に参加することも可能です。ただしサークル投稿を正常に処理できるソフトウェアは現在、kmyblue・Fedibirdに限ります。
- **PostgreSQL** 12+
- **Redis** 4+
- **Ruby** 2.7+
- **Node.js** 16+
また、通常のMastodonでは公開投稿を他のサーバーの人に自由に検索できるようにすることも可能ですが、kmyblueでは非収載投稿に対して同様の設定が可能です。つまり、ローカルタイムラインにも連合タイムラインにも流れない、誰かの目に自然に触れることはない、でも特定キーワードを使った検索では引っかかりたい、そのような需要に対応できます。
The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, **Scalingo**, and **Nanobox**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation.
内輪とは自分のサーバーに限ったものではありません。内輪同士で複数のサーバーを運営するとき、お互いが深く繋がれるフレンドサーバーというシステムも用意しています。
## Development
ただしkmyblueは、同時に連合も重視しています。ローカル限定投稿など、連合を大きく制限させるような機能は作る予定はありません。
### Vagrant
### 少人数サーバーでの運用
A **Vagrant** configuration is included for development purposes. To use it, complete the following steps:
kmyblueは、人の少ないサーバーでの運用を考慮して設計しています。そのため、他のサーバーのアカウントの購読機能はFedibirdほど発達していませんし、人の多いサーバー向けの独自改造もほとんど存在しません。
- Install Vagrant and Virtualbox
- Install the `vagrant-hostsupdater` plugin: `vagrant plugin install vagrant-hostsupdater`
- Run `vagrant up`
- Run `vagrant ssh -c "cd /vagrant && foreman start"`
- Open `http://mastodon.local` in your browser
ただしサーバーの負荷については一部度外視している部分があります。たとえば絵文字リアクション機能はサーバーへ著しい負荷をかける場合があります。絵文字リアクション機能そのものを無効にする管理者オプションも存在します。
### MacOS
もちろん人の多いサーバーでの運用が不便になるような修正は行っていません。人の多いサーバーでもそのままお使いいただけます。
To set up **MacOS** for native development, complete the following steps:
### 比較的高い防御力
- Install the latest stable Ruby version (use a Ruby version manager for easy installation and management of Ruby versions)
- Run `brew install postgresql@14`
- Run `brew install redis`
- Run `brew install imagemagick`
- Run `brew install libidn`
- Install Foreman or a similar tool (such as [overmind](https://github.com/DarthSim/overmind)) to handle multiple process launching.
- Navigate to Mastodon's root directory and run `brew install nvm` then `nvm use` to use the version from .nvmrc
- Run `corepack enable && corepack prepare`
- Run `bundle exec rails db:setup` (optionally prepend `RAILS_ENV=development` to target the dev environment)
- Finally, run `overmind start -f Procfile.dev`
kmyblueでは、「Fediverseは将来的に荒むのではないか」「Fediverseは将来的にスパムに溢れるのではないか」を念頭に設計している部分があります。
### Docker
個別ユーザー向けの設定項目が複数あります。
For development with **Docker**, complete the following steps:
- Misskeyは、たとえMastodonの投稿であっても非収載投稿を自由に検索できますが、kmyblueではそれをブロックできるユーザー設定が存在します
- 他の人からの絵文字リアクションの受け入れを制限する設定も可能であり、例えば他のサーバーから好ましくない絵文字リアクションを受け取ることを防止できます
- 公開タイムラインの引用表示はデフォルトで無効になっています。不快な投稿を引用したものが公開タイムラインに流れても、ある程度は防止できます
- フィルター(ワードミュート)は、引用された投稿の内容にも適用されます。この場合、引用投稿そのものが表示されなくなります
- 自分のフォローしている相手の投稿をフィルターから除外する設定が存在します。防御を上げすぎると不便な箇所が出てくるので、そちらも緩和できるよう可能な限り配慮しています
- Install Docker Desktop
- Run `docker compose -f .devcontainer/docker-compose.yml up -d`
- Run `docker compose -f .devcontainer/docker-compose.yml exec app .devcontainer/post-create.sh`
- Finally, run `docker compose -f .devcontainer/docker-compose.yml exec app foreman start -f Procfile.dev`
管理者向けには、スパムへの利用を前提とした正規表現可能なNGワード設定、細かい指定が可能な拡張ドメインブロック機能を用意しています。
If you are using an IDE with [support for the Development Container specification](https://containers.dev/supporting), it will run the above `docker compose` commands automatically. For **Visual Studio Code** this requires the [Dev Container extension](https://containers.dev/supporting#dev-containers).
ただし防御力の高さは自由を犠牲にします。例えばkmyblueは、絵文字リアクションの表示サイズ調整機能など、MisskeyやFedibirdには当たり前のようにある表示設定は存在しません。騒がしくなるようなものはあまり作りたいとは考えていません。
### GitHub Codespaces
### その他の主な機能
To get you coding in just a few minutes, GitHub Codespaces provides a web-based version of Visual Studio Code and a cloud-hosted development environment fully configured with the software needed for this project..
- 絵文字リアクションによる手軽な交流
- 絵文字デッキによる頻繁に使用する絵文字の登録・選択
- 検索機能の強化(検索許可)
- 投稿の引用
- ブックマークの分類
- Click this button to create a new codespace:<br>
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=52281283&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json)
- Wait for the environment to build. This will take a few minutes.
- When the editor is ready, run `foreman start -f Procfile.dev` in the terminal.
- After a few seconds, a popup will appear with a button labeled _Open in Browser_. This will open Mastodon.
- On the _Ports_ tab, right click on the “stream” row and select _Port visibility__Public_.
## kmyblueは何でないか
## Contributing
kmyblueは、Misskeyではありません。絵文字リアクションなどMisskeyと同様の機能はありますが、根本的にUIの使い勝手が違う他にも、例えばブックマークを分類できてもそれを公開する機能を作っていません。Misskeyは「楽しむ」をコンセプトにしていますが、kmyblueはMastodonの思想を受け継ぎ、炎上や喧騒を避けることのできる落ち着いた場所を目指しています。そのため、思想に合わない機能は実装しないか、大幅に弱体化しています。
Mastodon is **free, open-source software** licensed under **AGPLv3**.
kmyblueは、Fedibirdではありません。確かにローカルタイムラインを無効にしFedibirdのような運営を可能にする設定は存在します。しかしkmyblueは本家追従を優先する観点からWebで対応する範囲をある程度絞り込んでいるため、Fedibirdにあるような豊富な表示設定は作っていません。絵文字の大きさすら調整することはできません。また、Fedibirdではアカウントの購読機能があります。kmyblueにも同様の機能はあるものの、Fedibirdのように一発ですぐできるようなUIではありません。購読機能は相手のフォローを伴わないため、特に利用者に擬似的なフォロー体験を与えるアカウント購読は、人の少ない小規模サーバーには向いていません。これは、小規模サーバーの運用を想定しているkmyblueがあえて作っていない部分です。
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository or submit translations using Crowdin. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md). If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon).
kmyblueは、企業・政府機関向けに開発されたものではありません。そもそも管理者はセキュリティに関する資格や専門知識を有しておらず、高度なセキュリティの求められる機関向けのソフトウェアを制作する能力はありません。kmyblueは確かに本家Mastodonに対して大幅に機能を追加していますが、そもそも個人によるフォークは、開発者が飽きたらそこで終わりというリスクも伴います。高い信頼性・安全性を保証することはできないので、導入の際はご自身で安全を十分に確認してからお使いになることを強くおすすめします。
**IRC channel**: #mastodon on irc.libera.chat
## License
Copyright (C) 2016-2024 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md))
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

View file

@ -1,25 +1,20 @@
# セキュリティポリシー
# Security Policy
kmyblueのプログラムにおいてセキュリティインシデントを発見した場合、kmyblueに報告してください。
If you believe you've identified a security vulnerability in Mastodon (a bug that allows something to happen that shouldn't be possible), you can either:
kmyblueにセキュリティインシデントを報告する場合、以下の手順を踏んでください。
- open a [Github security issue on the Mastodon project](https://github.com/mastodon/mastodon/security/advisories/new)
- reach us at <security@joinmastodon.org>
- [こちらのリンクから新規インシデントを起票してください](https://github.com/kmycode/mastodon/security/advisories/new)
- メール <tt@kmycode.net>、または[@askyq@kmy.blue](https://kmy.blue/@askyq)宛に、**セキュリティインシデントを起票したことだけ**を連絡してください。セキュリティインシデントの内容は、絶対に連絡に含めないでください(リンクくらいなら含めていいかな)
You should _not_ report such issues on public GitHub issues or in other public spaces to give us time to publish a fix for the issue without exposing Mastodon's users to increased risk.
他のkmyblueフォークの利用者の安全のために少しでも時間稼ぎをしなければいけないので、この問題をIssueを含む公開された場所で記述しないでください。
## Scope
## 範囲
A "vulnerability in Mastodon" is a vulnerability in the code distributed through our main source code repository on GitHub. Vulnerabilities that are specific to a given installation (e.g. misconfiguration) should be reported to the owner of that installation and not us.
こちらが対応できる範囲は、当リポジトリで公開しているソースコードのみとなります。当リポジトリの依存パッケージ内に問題がある場合は、そちらに報告してください。
## Supported Versions
もしあなたに専門知識があり、それが本家Mastodon由来の問題であると信じるに足る根拠がある場合、kmyblueではなくMastodonのほうに報告してください。kmyblueに報告されても、Mastodonより先に修正してしまうことでMastodonにセキュリティリスクを発生させる可能性がありますし、本家Mastodonの対応を待つにしてもkmyblueのほうに来てしまったセキュリティインシデントの対応に困ります本家がなかなか対応してくれない可能性を考えると削除しづらい。もし間違ってkmyblueに来た場合、kmyblue開発者の責任で振り分けを行います。
## サポートするバージョン
下記以外のバージョンは、セキュリティインシデントを起票されても対応しません。
- 最新メジャーバージョン、かつ、最新マイナーバージョン
- 最新メジャーバージョンのサポートは、次のメジャーバージョンが出た時点で終了します
- LTS
- LTSのサポートは、次のLTSが出た時点で終了しますただし移行期間があってもいいと思ってるので、ヶ月以内ならセキュリティインシデントの程度に応じて対応する可能性があります
| Version | Supported |
| ------- | --------- |
| 4.2.x | Yes |
| 4.1.x | Yes |
| < 4.1 | No |

3
Vagrantfile vendored
View file

@ -173,7 +173,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# Otherwise, you can access the site at http://localhost:3000 and http://localhost:4000 , http://localhost:8080
config.vm.network :forwarded_port, guest: 3000, host: 3000
config.vm.network :forwarded_port, guest: 3035, host: 3035
config.vm.network :forwarded_port, guest: 4000, host: 4000
config.vm.network :forwarded_port, guest: 8080, host: 8080
config.vm.network :forwarded_port, guest: 9200, host: 9200
@ -189,7 +188,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.post_up_message = <<MESSAGE
To start server
$ vagrant ssh -c "cd /vagrant && bin/dev"
$ vagrant ssh -c "cd /vagrant && foreman start"
MESSAGE
end

View file

@ -3,28 +3,68 @@
class AccountsIndex < Chewy::Index
include DatetimeClampingConcern
# ElasticSearch config is moved to "/config/elasticsearch.default.yml".
# Edit it when original Mastodon changed ElasticSearch config.
settings index: index_preset(refresh_interval: '30s'), analysis: ChewyConfig.instance.accounts
settings index: index_preset(refresh_interval: '30s'), analysis: {
filter: {
english_stop: {
type: 'stop',
stopwords: '_english_',
},
english_stemmer: {
type: 'stemmer',
language: 'english',
},
english_possessive_stemmer: {
type: 'stemmer',
language: 'possessive_english',
},
},
analyzer: {
natural: {
tokenizer: 'standard',
filter: %w(
lowercase
asciifolding
cjk_width
elision
english_possessive_stemmer
english_stop
english_stemmer
),
},
verbatim: {
tokenizer: 'standard',
filter: %w(lowercase asciifolding cjk_width),
},
edge_ngram: {
tokenizer: 'edge_ngram',
filter: %w(lowercase asciifolding cjk_width),
},
},
tokenizer: {
edge_ngram: {
type: 'edge_ngram',
min_gram: 1,
max_gram: 15,
},
},
}
index_scope ::Account.searchable.includes(:account_stat)
root date_detection: false do
field(:id, type: 'long')
field(:following_count, type: 'long', value: ->(account) { account.public_following_count })
field(:followers_count, type: 'long', value: ->(account) { account.public_followers_count })
field(:following_count, type: 'long')
field(:followers_count, type: 'long')
field(:properties, type: 'keyword', value: ->(account) { account.searchable_properties })
field(:last_status_at, type: 'date', value: ->(account) { clamp_date(account.last_status_at || account.created_at) })
field(:domain, type: 'keyword', value: ->(account) { account.domain || '' })
field(:display_name, type: 'text', analyzer: ChewyConfig.instance.accounts_analyzers.dig('display_name', 'analyzer')) do
field :edge_ngram, type: 'text', analyzer: ChewyConfig.instance.accounts_analyzers.dig('display_name', 'edge_ngram', 'analyzer'), search_analyzer: ChewyConfig.instance.accounts_analyzers.dig('display_name', 'edge_ngram', 'search_analyzer')
end
field(:username, type: 'text', analyzer: ChewyConfig.instance.accounts_analyzers.dig('username', 'analyzer'), value: lambda { |account|
[account.username, account.domain].compact.join('@')
}) do
field :edge_ngram, type: 'text', analyzer: ChewyConfig.instance.accounts_analyzers.dig('username', 'edge_ngram', 'analyzer'),
search_analyzer: ChewyConfig.instance.accounts_analyzers.dig('username', 'edge_ngram', 'search_analyzer')
end
field(:text, type: 'text', analyzer: ChewyConfig.instance.accounts_analyzers.dig('text', 'analyzer'), value: ->(account) { account.searchable_text }) { field(:stemmed, type: 'text', analyzer: ChewyConfig.instance.accounts_analyzers.dig('text', 'stemmed', 'analyzer')) }
field(:display_name, type: 'text', analyzer: 'verbatim') { field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'verbatim' }
field(:username, type: 'text', analyzer: 'verbatim', value: ->(account) { [account.username, account.domain].compact.join('@') }) { field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'verbatim' }
field(:text, type: 'text', analyzer: 'verbatim', value: ->(account) { account.searchable_text }) { field :stemmed, type: 'text', analyzer: 'natural' }
end
end

View file

@ -3,22 +3,66 @@
class PublicStatusesIndex < Chewy::Index
include DatetimeClampingConcern
# ElasticSearch config is moved to "/config/elasticsearch.default.yml".
# Edit it when original Mastodon changed ElasticSearch config.
settings index: index_preset(refresh_interval: '30s', number_of_shards: 5), analysis: ChewyConfig.instance.public_statuses
settings index: index_preset(refresh_interval: '30s', number_of_shards: 5), analysis: {
filter: {
english_stop: {
type: 'stop',
stopwords: '_english_',
},
english_stemmer: {
type: 'stemmer',
language: 'english',
},
english_possessive_stemmer: {
type: 'stemmer',
language: 'possessive_english',
},
},
analyzer: {
verbatim: {
tokenizer: 'uax_url_email',
filter: %w(lowercase),
},
content: {
tokenizer: 'standard',
filter: %w(
lowercase
asciifolding
cjk_width
elision
english_possessive_stemmer
english_stop
english_stemmer
),
},
hashtag: {
tokenizer: 'keyword',
filter: %w(
word_delimiter_graph
lowercase
asciifolding
cjk_width
),
},
},
}
index_scope ::Status.unscoped
.kept
.indexable
.includes(:media_attachments, :preloadable_poll, :tags, :account, preview_cards_status: :preview_card)
.includes(:media_attachments, :preloadable_poll, :tags, preview_cards_status: :preview_card)
root date_detection: false do
field(:id, type: 'long')
field(:account_id, type: 'long')
field(:text, type: 'text', analyzer: ChewyConfig.instance.public_statuses_analyzers.dig('text', 'analyzer'), value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: ChewyConfig.instance.public_statuses_analyzers.dig('text', 'stemmed', 'analyzer')) }
field(:tags, type: 'text', analyzer: ChewyConfig.instance.public_statuses_analyzers.dig('tags', 'analyzer'), value: ->(status) { status.tags.map(&:display_name) })
field(:text, type: 'text', analyzer: 'verbatim', value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: 'content') }
field(:tags, type: 'text', analyzer: 'hashtag', value: ->(status) { status.tags.map(&:display_name) })
field(:language, type: 'keyword')
field(:domain, type: 'keyword', value: ->(status) { status.account.domain || '' })
field(:properties, type: 'keyword', value: ->(status) { status.searchable_properties })
field(:created_at, type: 'date', value: ->(status) { clamp_date(status.created_at) })
end

View file

@ -3,49 +3,64 @@
class StatusesIndex < Chewy::Index
include DatetimeClampingConcern
# ElasticSearch config is moved to "/config/elasticsearch.default.yml".
# Edit it when original Mastodon changed ElasticSearch config.
settings index: index_preset(refresh_interval: '30s', number_of_shards: 5), analysis: ChewyConfig.instance.statuses
settings index: index_preset(refresh_interval: '30s', number_of_shards: 5), analysis: {
filter: {
english_stop: {
type: 'stop',
stopwords: '_english_',
},
index_scope ::Status.unscoped.kept.without_reblogs.includes(
:account,
:media_attachments,
:local_mentioned,
:local_favorited,
:local_reblogged,
:local_bookmarked,
:local_emoji_reacted,
:tags,
:local_referenced,
preview_cards_status: :preview_card,
preloadable_poll: :local_voters
),
delete_if: lambda { |status|
if status.searchability == 'direct'
status.searchable_by.empty?
else
status.searchability == 'limited' ? !status.local? : false
end
}
english_stemmer: {
type: 'stemmer',
language: 'english',
},
english_possessive_stemmer: {
type: 'stemmer',
language: 'possessive_english',
},
},
analyzer: {
verbatim: {
tokenizer: 'uax_url_email',
filter: %w(lowercase),
},
content: {
tokenizer: 'standard',
filter: %w(
lowercase
asciifolding
cjk_width
elision
english_possessive_stemmer
english_stop
english_stemmer
),
},
hashtag: {
tokenizer: 'keyword',
filter: %w(
word_delimiter_graph
lowercase
asciifolding
cjk_width
),
},
},
}
index_scope ::Status.unscoped.kept.without_reblogs.includes(:media_attachments, :local_mentioned, :local_favorited, :local_reblogged, :local_bookmarked, :tags, preview_cards_status: :preview_card, preloadable_poll: :local_voters), delete_if: ->(status) { status.searchable_by.empty? }
root date_detection: false do
field(:id, type: 'long')
field(:account_id, type: 'long')
field(:text, type: 'text', analyzer: ChewyConfig.instance.statuses_analyzers.dig('text', 'analyzer'), value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: ChewyConfig.instance.statuses_analyzers.dig('text', 'stemmed', 'analyzer')) }
field(:tags, type: 'text', analyzer: ChewyConfig.instance.statuses_analyzers.dig('tags', 'analyzer'), value: ->(status) { status.tags.map(&:display_name) })
field(:text, type: 'text', analyzer: 'verbatim', value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: 'content') }
field(:tags, type: 'text', analyzer: 'hashtag', value: ->(status) { status.tags.map(&:display_name) })
field(:searchable_by, type: 'long', value: ->(status) { status.searchable_by })
field(:mentioned_by, type: 'long', value: ->(status) { status.mentioned_by })
field(:favourited_by, type: 'long', value: ->(status) { status.favourited_by })
field(:reblogged_by, type: 'long', value: ->(status) { status.reblogged_by })
field(:bookmarked_by, type: 'long', value: ->(status) { status.bookmarked_by })
field(:bookmark_categoried_by, type: 'long', value: ->(status) { status.bookmark_categoried_by })
field(:emoji_reacted_by, type: 'long', value: ->(status) { status.emoji_reacted_by })
field(:referenced_by, type: 'long', value: ->(status) { status.referenced_by })
field(:voted_by, type: 'long', value: ->(status) { status.voted_by })
field(:searchability, type: 'keyword', value: ->(status) { status.compute_searchability })
field(:visibility, type: 'keyword', value: ->(status) { status.searchable_visibility })
field(:language, type: 'keyword')
field(:domain, type: 'keyword', value: ->(status) { status.account.domain || '' })
field(:properties, type: 'keyword', value: ->(status) { status.searchable_properties })
field(:created_at, type: 'date', value: ->(status) { clamp_date(status.created_at) })
end

View file

@ -3,9 +3,36 @@
class TagsIndex < Chewy::Index
include DatetimeClampingConcern
# ElasticSearch config is moved to "/config/elasticsearch.default.yml".
# Edit it when original Mastodon changed ElasticSearch config.
settings index: index_preset(refresh_interval: '30s'), analysis: ChewyConfig.instance.tags
settings index: index_preset(refresh_interval: '30s'), analysis: {
analyzer: {
content: {
tokenizer: 'keyword',
filter: %w(
word_delimiter_graph
lowercase
asciifolding
cjk_width
),
},
edge_ngram: {
tokenizer: 'edge_ngram',
filter: %w(
lowercase
asciifolding
cjk_width
),
},
},
tokenizer: {
edge_ngram: {
type: 'edge_ngram',
min_gram: 2,
max_gram: 15,
},
},
}
index_scope ::Tag.listable
@ -14,9 +41,7 @@ class TagsIndex < Chewy::Index
end
root date_detection: false do
field(:name, type: 'text', analyzer: ChewyConfig.instance.tags_analyzers.dig('name', 'analyzer'), value: :display_name) do
field(:edge_ngram, type: 'text', analyzer: ChewyConfig.instance.tags_analyzers.dig('name', 'edge_ngram', 'analyzer'), search_analyzer: ChewyConfig.instance.tags_analyzers.dig('name', 'edge_ngram', 'search_analyzer'))
end
field(:name, type: 'text', analyzer: 'content', value: :display_name) { field(:edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content') }
field(:reviewed, type: 'boolean', value: ->(tag) { tag.reviewed? })
field(:usage, type: 'long', value: ->(tag, crutches) { tag.history.aggregate(crutches.time_period).accounts })
field(:last_status_at, type: 'date', value: ->(tag) { clamp_date(tag.last_status_at || tag.created_at) })

View file

@ -25,7 +25,7 @@ class AccountsController < ApplicationController
limit = params[:limit].present? ? [params[:limit].to_i, PAGE_SIZE_MAX].min : PAGE_SIZE
@statuses = filtered_statuses.without_reblogs.limit(limit)
@statuses = preload_collection(@statuses, Status)
@statuses = cache_collection(@statuses, Status)
end
format.json do
@ -46,11 +46,7 @@ class AccountsController < ApplicationController
end
def default_statuses
if current_account.present?
@account.statuses.distributable_visibility
else
@account.statuses.distributable_visibility_for_anonymous
end
@account.statuses.where(visibility: [:public, :unlisted])
end
def only_media_scope

View file

@ -1,9 +1,6 @@
# frozen_string_literal: true
class ActivityPub::BaseController < Api::BaseController
include SignatureVerification
include AccountOwnedConcern
skip_before_action :require_authenticated_user!
skip_before_action :require_not_suspended!
skip_around_action :set_locale

View file

@ -1,6 +1,9 @@
# frozen_string_literal: true
class ActivityPub::ClaimsController < ActivityPub::BaseController
include SignatureVerification
include AccountOwnedConcern
skip_before_action :authenticate_user!
before_action :require_account_signature!

View file

@ -1,6 +1,9 @@
# frozen_string_literal: true
class ActivityPub::CollectionsController < ActivityPub::BaseController
include SignatureVerification
include AccountOwnedConcern
vary_by -> { 'Signature' if authorized_fetch_mode? }
before_action :require_account_signature!, if: :authorized_fetch_mode?
@ -18,7 +21,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
def set_items
case params[:id]
when 'featured'
@items = for_signed_account { preload_collection(@account.pinned_statuses, Status) }
@items = for_signed_account { cache_collection(@account.pinned_statuses, Status) }
@items = @items.map { |item| item.distributable? ? item : ActivityPub::TagManager.instance.uri_for(item) }
when 'tags'
@items = for_signed_account { @account.featured_tags }

View file

@ -1,23 +0,0 @@
# frozen_string_literal: true
class ActivityPub::ContextsController < ActivityPub::BaseController
include SignatureVerification
vary_by -> { 'Signature' if authorized_fetch_mode? }
before_action :set_context
def show
expires_in 3.minutes, public: true
render json: @context,
serializer: ActivityPub::ContextSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
end
private
def set_context
@context = Conversation.find(params[:id])
end
end

View file

@ -1,6 +1,9 @@
# frozen_string_literal: true
class ActivityPub::FollowersSynchronizationsController < ActivityPub::BaseController
include SignatureVerification
include AccountOwnedConcern
vary_by -> { 'Signature' if authorized_fetch_mode? }
before_action :require_account_signature!
@ -21,7 +24,7 @@ class ActivityPub::FollowersSynchronizationsController < ActivityPub::BaseContro
end
def set_items
@items = @account.followers.matches_uri_prefix(uri_prefix).pluck(:uri)
@items = @account.followers.where(Account.arel_table[:uri].matches("#{Account.sanitize_sql_like(uri_prefix)}/%", false, true)).or(@account.followers.where(uri: uri_prefix)).pluck(:uri)
end
def collection_presenter

View file

@ -1,7 +1,9 @@
# frozen_string_literal: true
class ActivityPub::InboxesController < ActivityPub::BaseController
include SignatureVerification
include JsonLdHelper
include AccountOwnedConcern
before_action :skip_unknown_actor_activity
before_action :require_actor_signature!
@ -22,7 +24,7 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
def unknown_affected_account?
json = Oj.load(body, mode: :strict)
json.is_a?(Hash) && %w(Delete Update).include?(json['type']) && json['actor'].present? && json['actor'] == value_or_id(json['object']) && !Account.exists?(uri: json['actor'])
json.is_a?(Hash) && %w(Delete Update).include?(json['type']) && json['actor'].present? && json['actor'] == value_or_id(json['object']) && !Account.where(uri: json['actor']).exists?
rescue Oj::ParseError
false
end
@ -60,10 +62,11 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
return if raw_params.blank? || ENV['DISABLE_FOLLOWERS_SYNCHRONIZATION'] == 'true' || signed_request_account.nil?
# Re-using the syntax for signature parameters
params = SignatureParser.parse(raw_params)
tree = SignatureParamsParser.new.parse(raw_params)
params = SignatureParamsTransformer.new.apply(tree)
ActivityPub::PrepareFollowersSynchronizationService.new.call(signed_request_account, params)
rescue SignatureParser::ParsingError
rescue Parslet::ParseFailed
Rails.logger.warn 'Error parsing Collection-Synchronization header'
end

View file

@ -3,6 +3,9 @@
class ActivityPub::OutboxesController < ActivityPub::BaseController
LIMIT = 20
include SignatureVerification
include AccountOwnedConcern
vary_by -> { 'Signature' if authorized_fetch_mode? || page_requested? }
before_action :require_account_signature!, if: :authorized_fetch_mode?
@ -34,7 +37,7 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
ActivityPub::CollectionPresenter.new(
id: outbox_url,
type: :ordered,
size: @account.user&.setting_hide_statuses_count ? 0 : @account.statuses_count,
size: @account.statuses_count,
first: outbox_url(page: true),
last: outbox_url(page: true, min_id: 0)
)
@ -60,7 +63,7 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
def set_statuses
return unless page_requested?
@statuses = preload_collection_paginated_by_id(
@statuses = cache_collection_paginated_by_id(
AccountStatusesFilter.new(@account, signed_request_account).results,
Status,
LIMIT,

View file

@ -1,89 +0,0 @@
# frozen_string_literal: true
class ActivityPub::ReferencesController < ActivityPub::BaseController
include SignatureVerification
include Authorization
include AccountOwnedConcern
before_action :require_signature!, if: :authorized_fetch_mode?
before_action :set_status
def index
expires_in 0, public: public_fetch_mode?
render json: references_collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json', skip_activities: true
end
private
def pundit_user
signed_request_account
end
def set_status
@status = @account.statuses.find(params[:status_id])
authorize @status, :show?
rescue Mastodon::NotPermittedError
not_found
end
def load_statuses
cached_references
end
def cached_references
preload_collection(Status.where(id: results).reorder(:id), Status)
end
def results
@results ||= begin
references = @status.reference_objects.order(target_status_id: :asc)
references = references.where('target_status_id > ?', page_params[:min_id]) if page_params[:min_id].present?
references = references.limit(limit_param(references_limit))
references.pluck(:target_status_id)
end
end
def references_limit
StatusReference::REFERENCES_LIMIT
end
def pagination_min_id
results.last
end
def records_continue?
results.size == limit_param(references_limit)
end
def references_collection_presenter
page = ActivityPub::CollectionPresenter.new(
id: ActivityPub::TagManager.instance.references_uri_for(@status, page_params),
type: :unordered,
part_of: ActivityPub::TagManager.instance.references_uri_for(@status),
items: load_statuses.map(&:uri),
next: next_page
)
return page if page_requested?
ActivityPub::CollectionPresenter.new(
type: :unordered,
id: ActivityPub::TagManager.instance.references_uri_for(@status),
first: page
)
end
def page_requested?
truthy_param?(:page)
end
def next_page
return unless records_continue?
ActivityPub::TagManager.instance.references_uri_for(@status, page_params.merge(min_id: pagination_min_id))
end
def page_params
params_slice(:min_id, :limit).merge(page: true)
end
end

View file

@ -1,7 +1,9 @@
# frozen_string_literal: true
class ActivityPub::RepliesController < ActivityPub::BaseController
include SignatureVerification
include Authorization
include AccountOwnedConcern
DESCENDANTS_LIMIT = 60
@ -31,7 +33,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
def set_replies
@replies = only_other_accounts? ? Status.where.not(account_id: @account.id).joins(:account).merge(Account.without_suspended) : @account.statuses
@replies = @replies.distributable_visibility.where(in_reply_to_id: @status.id)
@replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
@replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
end

View file

@ -3,13 +3,13 @@
module Admin
class AccountsController < BaseController
before_action :set_account, except: [:index, :batch]
before_action :require_remote_account!, only: [:redownload, :approve_remote, :reject_remote]
before_action :require_remote_account!, only: [:redownload]
before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]
def index
authorize :account, :index?
@accounts = filtered_accounts.page(params[:page]).without_count
@accounts = filtered_accounts.page(params[:page])
@form = Form::AccountBatch.new
end
@ -66,20 +66,6 @@ module Admin
redirect_to admin_accounts_path(status: 'pending'), notice: I18n.t('admin.accounts.rejected_msg', username: @account.acct)
end
def approve_remote
authorize @account, :approve_remote?
@account.approve_remote!
log_action :approve_remote, @account
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.approved_msg', username: @account.acct)
end
def reject_remote
authorize @account, :reject_remote?
@account.reject_remote!
log_action :reject_remote, @account
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.rejected_msg', username: @account.acct)
end
def destroy
authorize @account, :destroy?
Admin::AccountDeletionWorker.perform_async(@account.id)
@ -142,7 +128,7 @@ module Admin
def unblock_email
authorize @account, :unblock_email?
CanonicalEmailBlock.matching_account(@account).delete_all
CanonicalEmailBlock.where(reference_account: @account).delete_all
log_action :unblock_email, @account
@ -182,12 +168,6 @@ module Admin
'approve'
elsif params[:reject]
'reject'
elsif params[:approve_remote]
'approve_remote'
elsif params[:approve_remote_domain]
'approve_remote_domain'
elsif params[:reject_remote]
'reject_remote'
end
end
end

View file

@ -6,7 +6,7 @@ module Admin
def index
authorize :audit_log, :index?
@auditable_accounts = Account.auditable.select(:id, :username)
@auditable_accounts = Account.where(id: Admin::ActionLog.select('distinct account_id')).select(:id, :username)
end
private

View file

@ -3,11 +3,11 @@
module Admin
class ConfirmationsController < BaseController
before_action :set_user
before_action :redirect_confirmed_user, only: [:resend], if: :user_confirmed?
before_action :check_confirmation, only: [:resend]
def create
authorize @user, :confirm?
@user.mark_email_as_confirmed!
@user.confirm!
log_action :confirm, @user
redirect_to admin_accounts_path
end
@ -25,13 +25,11 @@ module Admin
private
def redirect_confirmed_user
flash[:error] = I18n.t('admin.accounts.resend_confirmation.already_confirmed')
redirect_to admin_accounts_path
end
def user_confirmed?
@user.confirmed?
def check_confirmation
if @user.confirmed?
flash[:error] = I18n.t('admin.accounts.resend_confirmation.already_confirmed')
redirect_to admin_accounts_path
end
end
end
end

View file

@ -2,12 +2,10 @@
module Admin
class CustomEmojisController < BaseController
before_action :set_custom_emoji, only: [:edit, :update]
def index
authorize :custom_emoji, :index?
@custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page]).without_count
@custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])
@form = Form::CustomEmojiBatch.new
end
@ -17,10 +15,6 @@ module Admin
@custom_emoji = CustomEmoji.new
end
def edit
authorize :custom_emoji, :create?
end
def create
authorize :custom_emoji, :create?
@ -34,19 +28,6 @@ module Admin
end
end
def update
authorize :custom_emoji, :create?
@custom_emoji.assign_attributes(update_params)
if @custom_emoji.save
log_action :update, @custom_emoji
redirect_to admin_custom_emojis_path(filter_params), notice: I18n.t('admin.custom_emojis.updated_msg')
else
render :new
end
end
def batch
authorize :custom_emoji, :index?
@ -62,16 +43,8 @@ module Admin
private
def set_custom_emoji
@custom_emoji = CustomEmoji.find(params[:id])
end
def resource_params
params.require(:custom_emoji).permit(:shortcode, :image, :category_id, :visible_in_picker, :aliases_raw, :license)
end
def update_params
params.require(:custom_emoji).permit(:category_id, :visible_in_picker, :aliases_raw, :license)
params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker)
end
def filtered_custom_emojis

View file

@ -25,8 +25,6 @@ class Admin::DomainAllowsController < Admin::BaseController
def destroy
authorize @domain_allow, :destroy?
UnallowDomainService.new.call(@domain_allow)
log_action :destroy, @domain_allow
redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.destroyed_msg')
end

View file

@ -88,19 +88,15 @@ module Admin
end
def update_params
params.require(:domain_block).permit(:severity, :reject_media, :reject_favourite, :reject_reply_exclude_followers, :reject_send_sensitive, :reject_hashtag,
:reject_straight_follow, :reject_new_follow, :reject_friend, :block_trends, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden)
params.require(:domain_block).permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate)
end
def resource_params
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_favourite, :reject_reply_exclude_followers, :reject_send_sensitive, :reject_hashtag,
:reject_straight_follow, :reject_new_follow, :reject_friend, :block_trends, :detect_invalid_subscription, :reject_reports, :private_comment, :public_comment, :obfuscate, :hidden)
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate)
end
def form_domain_block_batch_params
params.require(:form_domain_block_batch).permit(domain_blocks_attributes: [:enabled, :domain, :severity, :reject_media, :reject_favourite, :reject_reply_exclude_followers,
:reject_send_sensitive, :reject_hashtag, :reject_straight_follow, :reject_new_follow, :reject_friend, :block_trends, :detect_invalid_subscription,
:reject_reports, :private_comment, :public_comment, :obfuscate, :hidden])
params.require(:form_domain_block_batch).permit(domain_blocks_attributes: [:enabled, :domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate])
end
def action_from_button

View file

@ -38,7 +38,7 @@ module Admin
log_action :create, @email_domain_block
(@email_domain_block.other_domains || []).uniq.each do |domain|
next if EmailDomainBlock.exists?(domain: domain)
next if EmailDomainBlock.where(domain: domain).exists?
other_email_domain_block = EmailDomainBlock.create!(domain: domain, allow_with_approval: @email_domain_block.allow_with_approval, parent: @email_domain_block)
log_action :create, other_email_domain_block

View file

@ -36,17 +36,7 @@ module Admin
reject_reports: row.fetch('#reject_reports', false),
private_comment: @global_private_comment,
public_comment: row['#public_comment'],
obfuscate: row.fetch('#obfuscate', false),
reject_favourite: row.fetch('#reject_favourite', false),
reject_send_sensitive: row.fetch('#reject_send_sensitive', false),
reject_hashtag: row.fetch('#reject_hashtag', false),
reject_straight_follow: row.fetch('#reject_straight_follow', false),
reject_new_follow: row.fetch('#reject_new_follow', false),
hidden: row.fetch('#hidden', false),
detect_invalid_subscription: row.fetch('#detect_invalid_subscription', false),
reject_reply_exclude_followers: row.fetch('#reject_reply_exclude_followers', false),
reject_friend: row.fetch('#reject_friend', false),
block_trends: row.fetch('#block_trends', false))
obfuscate: row.fetch('#obfuscate', false))
if domain_block.invalid?
flash.now[:alert] = I18n.t('admin.export_domain_blocks.invalid_domain_block', error: domain_block.errors.full_messages.join(', '))
@ -59,7 +49,7 @@ module Admin
next
end
@warning_domains = instances_from_imported_blocks.pluck(:domain)
@warning_domains = Instance.where(domain: @domain_blocks.map(&:domain)).where('EXISTS (SELECT 1 FROM follows JOIN accounts ON follows.account_id = accounts.id OR follows.target_account_id = accounts.id WHERE accounts.domain = instances.domain)').pluck(:domain)
rescue ActionController::ParameterMissing
flash.now[:alert] = I18n.t('admin.export_domain_blocks.no_file')
set_dummy_import!
@ -68,56 +58,18 @@ module Admin
private
def instances_from_imported_blocks
Instance.with_domain_follows(@domain_blocks.map(&:domain))
end
def export_filename
'domain_blocks.csv'
end
def export_headers
%w(
#domain
#severity
#reject_media
#reject_reports
#public_comment
#obfuscate
#reject_favourite
#reject_send_sensitive
#reject_hashtag
#reject_straight_follow
#reject_new_follow
#hidden
#detect_invalid_subscription
#reject_reply_exclude_followers
#reject_friend
#block_trends
)
%w(#domain #severity #reject_media #reject_reports #public_comment #obfuscate)
end
def export_data
CSV.generate(headers: export_headers, write_headers: true) do |content|
DomainBlock.with_limitations.order(id: :asc).each do |instance|
content << [
instance.domain,
instance.severity,
instance.reject_media,
instance.reject_reports,
instance.public_comment,
instance.obfuscate,
instance.reject_favourite,
instance.reject_send_sensitive,
instance.reject_hashtag,
instance.reject_straight_follow,
instance.reject_new_follow,
instance.hidden,
instance.detect_invalid_subscription,
instance.reject_reply_exclude_followers,
instance.reject_friend,
instance.block_trends,
]
content << [instance.domain, instance.severity, instance.reject_media, instance.reject_reports, instance.public_comment, instance.obfuscate]
end
end
end

View file

@ -1,93 +0,0 @@
# frozen_string_literal: true
module Admin
class FriendServersController < BaseController
before_action :set_friend, except: [:index, :new, :create]
before_action :warn_signatures_not_enabled!, only: [:new, :edit, :create, :follow, :unfollow, :accept, :reject]
def index
authorize :friend_server, :update?
@friends = FriendDomain.all
end
def new
authorize :friend_server, :update?
@friend = FriendDomain.new
end
def edit
authorize :friend_server, :update?
end
def create
authorize :friend_server, :update?
@friend = FriendDomain.new(resource_params)
if @friend.save
@friend.follow!
redirect_to admin_friend_servers_path
else
render action: :new
end
end
def update
authorize :friend_server, :update?
if @friend.update(update_resource_params)
redirect_to admin_friend_servers_path
else
render action: :edit
end
end
def destroy
authorize :friend_server, :update?
@friend.destroy
redirect_to admin_friend_servers_path
end
def follow
authorize :friend_server, :update?
@friend.follow!
render action: :edit
end
def unfollow
authorize :friend_server, :update?
@friend.unfollow!
render action: :edit
end
def accept
authorize :friend_server, :update?
@friend.accept!
render action: :edit
end
def reject
authorize :friend_server, :update?
@friend.reject!
render action: :edit
end
private
def set_friend
@friend = FriendDomain.find(params[:id])
end
def resource_params
params.require(:friend_domain).permit(:domain, :inbox_url, :available, :pseudo_relay, :delivery_local, :unlocked, :allow_all_posts)
end
def update_resource_params
params.require(:friend_domain).permit(:inbox_url, :available, :pseudo_relay, :delivery_local, :unlocked, :allow_all_posts)
end
def warn_signatures_not_enabled!
flash.now[:error] = I18n.t('admin.relays.signatures_not_enabled') if authorized_fetch_mode?
end
end
end

View file

@ -1,24 +0,0 @@
# frozen_string_literal: true
module Admin
class NgRuleHistoriesController < BaseController
before_action :set_ng_rule
before_action :set_histories
PER_PAGE = 20
def show
authorize :ng_words, :show?
end
private
def set_ng_rule
@ng_rule = ::NgRule.find(params[:id])
end
def set_histories
@histories = NgRuleHistory.where(ng_rule_id: params[:id]).order(id: :desc).page(params[:page]).per(PER_PAGE)
end
end
end

View file

@ -1,115 +0,0 @@
# frozen_string_literal: true
module Admin
class NgRulesController < BaseController
before_action :set_ng_rule, only: [:edit, :update, :destroy, :duplicate]
def index
authorize :ng_words, :show?
@ng_rules = ::NgRule.order(id: :asc)
end
def new
authorize :ng_words, :show?
@ng_rule = ::NgRule.build
end
def edit
authorize :ng_words, :show?
end
def create
authorize :ng_words, :create?
begin
test_words!
rescue
flash[:alert] = I18n.t('admin.ng_rules.test_error')
redirect_to new_admin_ng_rule_path
return
end
@ng_rule = ::NgRule.build(resource_params)
if @ng_rule.save
redirect_to admin_ng_rules_path
else
render :new
end
end
def update
authorize :ng_words, :create?
begin
test_words!
rescue
flash[:alert] = I18n.t('admin.ng_rules.test_error')
redirect_to edit_admin_ng_rule_path(id: @ng_rule.id)
return
end
if @ng_rule.update(resource_params)
redirect_to admin_ng_rules_path
else
render :edit
end
end
def duplicate
authorize :ng_words, :create?
@ng_rule = @ng_rule.copy!
flash[:alert] = I18n.t('admin.ng_rules.copy_error') unless @ng_rule.save
redirect_to admin_ng_rules_path
end
def destroy
authorize :ng_words, :create?
@ng_rule.destroy
redirect_to admin_ng_rules_path
end
private
def set_ng_rule
@ng_rule = ::NgRule.find(params[:id])
end
def resource_params
params.require(:ng_rule).permit(:title, :expires_in, :available, :account_domain, :account_username, :account_display_name,
:account_note, :account_field_name, :account_field_value, :account_avatar_state,
:account_header_state, :account_include_local, :status_spoiler_text, :status_text, :status_tag,
:status_sensitive_state, :status_cw_state, :status_media_state, :status_poll_state,
:status_mention_state, :status_reference_state,
:status_quote_state, :status_reply_state, :status_media_threshold, :status_poll_threshold,
:status_mention_threshold, :status_allow_follower_mention,
:reaction_allow_follower, :emoji_reaction_name, :emoji_reaction_origin_domain,
:status_reference_threshold, :account_allow_followed_by_local, :record_history_also_local,
status_visibility: [], status_searchability: [], reaction_type: [])
end
def test_words!
arr = [
resource_params[:account_domain],
resource_params[:account_username],
resource_params[:account_display_name],
resource_params[:account_note],
resource_params[:account_field_name],
resource_params[:account_field_value],
resource_params[:status_spoiler_text],
resource_params[:status_text],
resource_params[:status_tag],
resource_params[:emoji_reaction_name],
resource_params[:emoji_reaction_origin_domain],
].compact_blank.join("\n")
Admin::NgRule.extract_test!(arr) if arr.present?
end
end
end

View file

@ -1,30 +0,0 @@
# frozen_string_literal: true
module Admin
class NgWords::KeywordsController < NgWordsController
def show
super
@ng_words = ::NgWord.caches.presence || [::NgWord.new]
end
protected
def validate
begin
::NgWord.save_from_raws(settings_params_test)
return true
rescue
flash[:alert] = I18n.t('admin.ng_words.test_error')
redirect_to after_update_redirect_path
end
false
end
private
def after_update_redirect_path
admin_ng_words_keywords_path
end
end
end

View file

@ -1,11 +0,0 @@
# frozen_string_literal: true
module Admin
class NgWords::SettingsController < NgWordsController
protected
def after_update_redirect_path
admin_ng_words_settings_path
end
end
end

View file

@ -1,34 +0,0 @@
# frozen_string_literal: true
module Admin
class NgWords::WhiteListController < NgWordsController
def show
super
@white_list_domains = SpecifiedDomain.white_list_domain_caches.presence || [SpecifiedDomain.new]
end
protected
def validate
begin
SpecifiedDomain.save_from_raws_as_white_list(settings_params_list)
return true
rescue
flash[:alert] = I18n.t('admin.ng_words.save_error')
redirect_to after_update_redirect_path
end
false
end
def after_update_redirect_path
admin_ng_words_white_list_path
end
private
def settings_params_list
params.require(:form_admin_settings)[:specified_domains]
end
end
end

View file

@ -1,46 +0,0 @@
# frozen_string_literal: true
module Admin
class NgWordsController < BaseController
def show
authorize :ng_words, :show?
@admin_settings = Form::AdminSettings.new
end
def create
authorize :ng_words, :create?
return unless validate
@admin_settings = Form::AdminSettings.new(settings_params)
if @admin_settings.save
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to after_update_redirect_path
else
render :show
end
end
protected
def validate
true
end
def after_update_redirect_path
admin_ng_words_path
end
private
def settings_params
params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS)
end
def settings_params_test
params.require(:form_admin_settings)[:ng_words_test]
end
end
end

View file

@ -1,19 +0,0 @@
# frozen_string_literal: true
module Admin
class NgwordHistoriesController < BaseController
before_action :set_histories
PER_PAGE = 20
def index
authorize :ng_words, :show?
end
private
def set_histories
@histories = NgwordHistory.order(id: :desc).page(params[:page]).per(PER_PAGE)
end
end
end

View file

@ -12,7 +12,7 @@ class Admin::Reports::ActionsController < Admin::BaseController
authorize @report, :show?
case action_from_button
when 'delete', 'mark_as_sensitive', 'force_cw'
when 'delete', 'mark_as_sensitive'
status_batch_action = Admin::StatusBatchAction.new(
type: action_from_button,
status_ids: @report.status_ids,
@ -52,8 +52,6 @@ class Admin::Reports::ActionsController < Admin::BaseController
'delete'
elsif params[:mark_as_sensitive]
'mark_as_sensitive'
elsif params[:force_cw]
'force_cw'
elsif params[:silence]
'silence'
elsif params[:suspend]

View file

@ -53,7 +53,7 @@ module Admin
end
def resource_params
params.require(:rule).permit(:text, :hint, :priority)
params.require(:rule).permit(:text, :priority)
end
end
end

View file

@ -1,47 +0,0 @@
# frozen_string_literal: true
module Admin
class SensitiveWordsController < BaseController
def show
authorize :sensitive_words, :show?
@admin_settings = Form::AdminSettings.new
@sensitive_words = ::SensitiveWord.caches.presence || [::SensitiveWord.new]
end
def create
authorize :sensitive_words, :create?
begin
::SensitiveWord.save_from_raws(settings_params_test)
rescue
flash[:alert] = I18n.t('admin.ng_words.test_error')
redirect_to after_update_redirect_path
return
end
@admin_settings = Form::AdminSettings.new(settings_params)
if @admin_settings.save
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to after_update_redirect_path
else
render :index
end
end
private
def after_update_redirect_path
admin_sensitive_words_path
end
def settings_params
params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS)
end
def settings_params_test
params.require(:form_admin_settings)[:sensitive_words_test]
end
end
end

View file

@ -1,18 +1,9 @@
# frozen_string_literal: true
class Admin::Settings::RegistrationsController < Admin::SettingsController
include RegistrationLimitationHelper
before_action :set_limitation_counts, only: :show # rubocop:disable Rails/LexicallyScopedActionFilter
private
def after_update_redirect_path
admin_settings_registrations_path
end
def set_limitation_counts
@current_users_count = user_count_for_registration
@current_users_count_today = today_increase_user_count
end
end

View file

@ -9,7 +9,7 @@ module Admin
@site_upload.destroy!
redirect_back fallback_location: admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
redirect_to admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
end
private

View file

@ -1,34 +0,0 @@
# frozen_string_literal: true
module Admin
class SpecialDomainsController < BaseController
def show
authorize :instance, :show?
@admin_settings = Form::AdminSettings.new
end
def create
authorize :instance, :destroy?
@admin_settings = Form::AdminSettings.new(settings_params)
if @admin_settings.save
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to after_update_redirect_path
else
render :show
end
end
private
def after_update_redirect_path
admin_special_domains_path
end
def settings_params
params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS)
end
end
end

View file

@ -1,34 +0,0 @@
# frozen_string_literal: true
module Admin
class SpecialInstancesController < BaseController
def show
authorize :instance, :show?
@admin_settings = Form::AdminSettings.new
end
def create
authorize :instance, :destroy?
@admin_settings = Form::AdminSettings.new(settings_params)
if @admin_settings.save
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to after_update_redirect_path
else
render :show
end
end
private
def after_update_redirect_path
admin_special_instances_path
end
def settings_params
params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS)
end
end
end

View file

@ -4,7 +4,7 @@ module Admin
class StatusesController < BaseController
before_action :set_account
before_action :set_statuses, except: :show
before_action :set_status, only: [:show, :remove_history, :remove_media, :force_sensitive, :force_cw, :remove_status]
before_action :set_status, only: :show
PER_PAGE = 20
@ -29,65 +29,6 @@ module Admin
redirect_to after_create_redirect_path
end
def remove_history
authorize [:admin, @status], :show?
UpdateStatusService.new.call(
@status,
edit_status_account_id,
no_history: true,
bypass_validation: true
)
log_action(:remove_history, @status)
redirect_to admin_account_status_path
end
def remove_media
authorize [:admin, @status], :show?
UpdateStatusService.new.call(
@status,
edit_status_account_id,
media_ids: [],
media_attributes: [],
bypass_validation: true
)
log_action(:remove_media, @status)
redirect_to admin_account_status_path
end
def force_sensitive
authorize [:admin, @status], :show?
UpdateStatusService.new.call(
@status,
edit_status_account_id,
sensitive: true,
bypass_validation: true
)
log_action(:force_sensitive, @status)
redirect_to admin_account_status_path
end
def force_cw
authorize [:admin, @status], :show?
UpdateStatusService.new.call(
@status,
edit_status_account_id,
spoiler_text: 'CW',
bypass_validation: true
)
log_action(:force_cw, @status)
redirect_to admin_account_status_path
end
def remove_status
authorize [:admin, @status], :show?
@status.discard_with_reblogs
StatusPin.find_by(status: @status)&.destroy
@status.account.statuses_count = @status.account.statuses_count - 1
RemovalWorker.perform_async(@status.id, { 'redraft' => false })
log_action(:remove_status, @status)
redirect_to admin_account_path
end
private
def batched_ordered_status_edits
@ -121,13 +62,6 @@ module Admin
@statuses = Admin::StatusFilter.new(@account, filter_params).results.preload(:application, :preloadable_poll, :media_attachments, active_mentions: :account, reblog: [:account, :application, :preloadable_poll, :media_attachments, active_mentions: :account]).page(params[:page]).per(PER_PAGE)
end
def edit_status_account_id
return @edit_account_id || @account.id if @edit_account_checked
@edit_account_checked = true
@edit_account_id = Account.representative.id
end
def filter_params
params.slice(*Admin::StatusFilter::KEYS).permit(*Admin::StatusFilter::KEYS)
end

View file

@ -1,51 +0,0 @@
# frozen_string_literal: true
class AntennasController < ApplicationController
layout 'admin'
before_action :authenticate_user!
before_action :set_antenna, only: [:edit, :update, :destroy]
before_action :set_body_classes
before_action :set_cache_headers
def index
@antennas = current_account.antennas.includes(:antenna_domains).includes(:antenna_tags).includes(:antenna_accounts)
end
def edit; end
def update
if @antenna.update(resource_params)
redirect_to antennas_path
else
render action: :edit
end
end
def destroy
@antenna.destroy
redirect_to antennas_path
end
private
def set_antenna
@antenna = current_account.antennas.find(params[:id])
end
def resource_params
params.require(:antenna).permit(:title, :available, :expires_in)
end
def thin_resource_params
params.require(:antenna).permit(:title)
end
def set_body_classes
@body_classes = 'admin'
end
def set_cache_headers
response.cache_control.replace(private: true, no_store: true)
end
end

View file

@ -1,15 +1,13 @@
# frozen_string_literal: true
class Api::BaseController < ApplicationController
DEFAULT_STATUSES_LIMIT = 20
DEFAULT_ACCOUNTS_LIMIT = 40
DEFAULT_STATUSES_LIMIT = 20
DEFAULT_ACCOUNTS_LIMIT = 40
include Api::RateLimitHeaders
include Api::AccessTokenTrackingConcern
include Api::CachingConcern
include Api::ContentSecurityPolicy
include Api::ErrorHandling
include Api::Pagination
skip_before_action :require_functional!, unless: :limited_federation_mode?
@ -20,6 +18,51 @@ class Api::BaseController < ApplicationController
protect_from_forgery with: :null_session
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
render json: { error: e.to_s }, status: 422
end
rescue_from ActiveRecord::RecordNotUnique do
render json: { error: 'Duplicate record' }, status: 422
end
rescue_from Date::Error do
render json: { error: 'Invalid date supplied' }, status: 422
end
rescue_from ActiveRecord::RecordNotFound do
render json: { error: 'Record not found' }, status: 404
end
rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
render json: { error: 'Remote data could not be fetched' }, status: 503
end
rescue_from OpenSSL::SSL::SSLError do
render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
end
rescue_from Mastodon::NotPermittedError do
render json: { error: 'This action is not allowed' }, status: 403
end
rescue_from Seahorse::Client::NetworkingError do |e|
Rails.logger.warn "Storage server error: #{e}"
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight do
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end
rescue_from Mastodon::RateLimitExceededError do
render json: { error: I18n.t('errors.429') }, status: 429
end
rescue_from ActionController::ParameterMissing, Mastodon::InvalidParameterError do |e|
render json: { error: e.to_s }, status: 400
end
def doorkeeper_unauthorized_render_options(error: nil)
{ json: { error: error.try(:description) || 'Not authorized' } }
end
@ -30,6 +73,13 @@ class Api::BaseController < ApplicationController
protected
def set_pagination_headers(next_path = nil, prev_path = nil)
links = []
links << [next_path, [%w(rel next)]] if next_path
links << [prev_path, [%w(rel prev)]] if prev_path
response.headers['Link'] = LinkHeader.new(links) unless links.empty?
end
def limit_param(default_limit)
return default_limit unless params[:limit]
@ -58,6 +108,10 @@ class Api::BaseController < ApplicationController
render json: { error: 'Your login is currently disabled' }, status: 403 if current_user&.account&.unavailable?
end
def require_valid_pagination_options!
render json: { error: 'Pagination values for `offset` and `limit` must be positive' }, status: 400 if pagination_options_invalid?
end
def require_user!
if !current_user
render json: { error: 'This method requires an authenticated user' }, status: 422
@ -86,6 +140,10 @@ class Api::BaseController < ApplicationController
private
def pagination_options_invalid?
params.slice(:limit, :offset).values.map(&:to_i).any?(&:negative?)
end
def respond_with_error(code)
render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code
end

View file

@ -1,18 +0,0 @@
# frozen_string_literal: true
class Api::V1::Accounts::AntennasController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:lists' }
before_action :require_user!
before_action :set_account
def index
@antennas = @account.suspended? ? [] : @account.joined_antennas.where(account: current_account)
render json: @antennas, each_serializer: REST::AntennaSerializer
end
private
def set_account
@account = Account.find(params[:account_id])
end
end

View file

@ -1,18 +0,0 @@
# frozen_string_literal: true
class Api::V1::Accounts::CirclesController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:lists' }
before_action :require_user!
before_action :set_account
def index
@circles = @account.suspended? ? [] : @account.joined_circles.where(account: current_account)
render json: @circles, each_serializer: REST::CircleSerializer
end
private
def set_account
@account = Account.find(params[:account_id])
end
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class Api::V1::Accounts::CredentialsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:accounts', :'read:me' }, except: [:update]
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, except: [:update]
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update]
before_action :require_user!
@ -31,8 +31,6 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
:locked,
:bot,
:discoverable,
:searchability,
:dissubscribable,
:hide_collections,
:indexable,
fields_attributes: [:name, :value]
@ -47,7 +45,6 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
{
settings_attributes: {
default_privacy: source_params.fetch(:privacy, @account.user.setting_default_privacy),
default_searchability: source_params.fetch(:searchability, @account.user.setting_default_searchability),
default_sensitive: source_params.fetch(:sensitive, @account.user.setting_default_sensitive),
default_language: source_params.fetch(:language, @account.user.setting_default_language),
},

View file

@ -1,18 +0,0 @@
# frozen_string_literal: true
class Api::V1::Accounts::ExcludeAntennasController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:lists' }
before_action :require_user!
before_action :set_account
def index
@antennas = @account.suspended? ? [] : current_account.antennas.where('exclude_accounts @> \'[?]\'', @account.id)
render json: @antennas, each_serializer: REST::AntennaSerializer
end
private
def set_account
@account = Account.find(params[:account_id])
end
end

View file

@ -21,7 +21,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
return [] if hide_results?
scope = default_accounts
scope = scope.not_excluded_by_account(current_account) unless current_account.nil? || current_account.id == @account.id
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id
scope.merge(paginated_follows).to_a
end
@ -30,7 +30,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
end
def default_accounts
Account.includes(:active_relationships, :account_stat, :user).references(:active_relationships)
Account.includes(:active_relationships, :account_stat).references(:active_relationships)
end
def paginated_follows
@ -41,6 +41,10 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
)
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path
api_v1_account_followers_url pagination_params(max_id: pagination_max_id) if records_continue?
end

Some files were not shown because too many files have changed in this diff Show more