summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.config/example.yml61
-rw-r--r--CHANGELOG.md3
-rw-r--r--locales/index.d.ts40
-rw-r--r--locales/ja-JP.yml10
-rw-r--r--packages/backend/migration/1707808106310-MakeRepositoryUrlNullable.js16
-rw-r--r--packages/backend/src/config.ts4
-rw-r--r--packages/backend/src/models/Meta.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/admin/meta.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/update-meta.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/meta.ts9
-rw-r--r--packages/frontend/src/boot/main-boot.ts8
-rw-r--r--packages/frontend/src/components/MkSourceCodeAvailablePopup.vue112
-rw-r--r--packages/frontend/src/local-storage.ts1
-rw-r--r--packages/frontend/src/pages/about-misskey.vue24
-rw-r--r--packages/frontend/src/pages/about.vue40
-rw-r--r--packages/frontend/src/pages/admin/branding.vue16
-rw-r--r--packages/frontend/src/pages/admin/settings.vue15
-rw-r--r--packages/misskey-js/src/autogen/types.ts11
-rw-r--r--scripts/build-assets.mjs15
19 files changed, 371 insertions, 26 deletions
diff --git a/.config/example.yml b/.config/example.yml
index 3c9c3bc0d7..7fea929374 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -2,6 +2,63 @@
# Misskey configuration
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+# ┌──────────────────────────────┐
+#───┘ a boring but important thing └────────────────────────────
+
+#
+# First of all, let me tell you a story that may possibly be
+# boring to you and possibly important to you.
+#
+# Misskey is licensed under the AGPLv3 license. This license is
+# known to be often misunderstood. Please read the following
+# instructions carefully and select the appropriate option so
+# that you do not negligently cause a license violation.
+#
+
+# --------
+# Option 1: If you host Misskey AS-IS (without any changes to
+# the source code. forks are not included).
+#
+# Step 1: Congratulations! You don't need to do anything.
+
+# --------
+# Option 2: If you have made changes to the source code (forks
+# are included) and publish a Git repository of source
+# code. There should be no access restrictions on
+# this repository. Strictly speaking, it doesn't have
+# to be a Git repository, but you'll probably use Git!
+#
+# Step 1: Build and run the Misskey server first.
+# Step 2: Open <https://your.misskey.example/admin/settings> in
+# your browser with the administrator account.
+# Step 3: Enter the URL of your Git repository in the
+# "Repository URL" field.
+
+# --------
+# Option 3: If neither of the above applies to you.
+# (In this case, the source code should be published
+# on the Misskey interface. IT IS NOT ENOUGH TO
+# DISCLOSE THE SOURCE CODE WEHN A USER REQUESTS IT BY
+# E-MAIL OR OTHER MEANS. If you are not satisfied
+# with this, it is recommended that you read the
+# license again carefully. Anyway, enabling this
+# option will automatically generate and publish a
+# tarball at build time, protecting you from
+# inadvertent license violations. (There is no legal
+# guarantee, of course.) The tarball will generated
+# from the root directory of your codebase. So it is
+# also recommended to check <built/tarball> directory
+# once after building and before activating the server
+# to avoid ACCIDENTAL LEAKING OF SENSITIVE INFORMATION.
+# To prevent certain files from being included in the
+# tarball, add a glob pattern after line 15 in
+# <scripts/tarball.mjs>. DO NOT FORGET TO BUILD AFTER
+# ENABLING THIS OPTION!)
+#
+# Step 1: Uncomment the following line.
+#
+# publishTarballInsteadOfProvideRepositoryUrl: true
+
# ┌─────┐
#───┘ URL └─────────────────────────────────────────────────────
@@ -118,7 +175,7 @@ redis:
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
-# You can set scope to local (default value) or global
+# You can set scope to local (default value) or global
# (include notes from remote).
#meilisearch:
@@ -214,7 +271,7 @@ proxyRemoteFiles: true
signToActivityPubGet: true
# For security reasons, uploading attachments from the intranet is prohibited,
-# but exceptions can be made from the following settings. Default value is "undefined".
+# but exceptions can be made from the following settings. Default value is "undefined".
# Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
#allowedPrivateNetworks: [
# '127.0.0.1/32'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b6db0b61ef..e70a3e3413 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,9 @@
### General
- Feat: [mCaptcha](https://github.com/mCaptcha/mCaptcha)のサポートを追加
- Feat: Add support for TrueMail
+- Feat: AGPLv3ライセンスに誤って違反するのを防止する機能を追加
+ - 管理者がrepositoryUrlを変更したり、またはソースコードを直接頒布することを選択できるようになります
+ - 本体のソースコードに改変を加えた際に、ライセンスに基づく適切な案内を表示します
- Enhance: モデレーターはすべてのユーザーのリアクション一覧を見られるように
- Fix: リストライムラインの「リノートを表示」が正しく機能しない問題を修正
- Fix: リモートユーザーのリアクション一覧がすべて見えてしまうのを修正
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 8f4c9d18e4..1bc99ab849 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -3981,6 +3981,10 @@ export interface Locale extends ILocale {
*/
"pleaseDonate": ParameterizedString<"host">;
/**
+ * 対応するソースコードは{anchor}から利用可能です。
+ */
+ "correspondingSourceIsAvailable": ParameterizedString<"anchor">;
+ /**
* ロール
*/
"roles": string;
@@ -4685,6 +4689,34 @@ export interface Locale extends ILocale {
*/
"externalServices": string;
/**
+ * ソースコード
+ */
+ "sourceCode": string;
+ /**
+ * ソースコードはまだ提供されていません。この問題の修正について管理者に問い合わせてください。
+ */
+ "sourceCodeIsNotYetProvided": string;
+ /**
+ * リポジトリURL
+ */
+ "repositoryUrl": string;
+ /**
+ * ソースコードが公開されているリポジトリがある場合、そのURLを記入します。Misskeyを現状のまま(ソースコードにいかなる変更も加えずに)使用している場合は https://github.com/misskey-dev/misskey と記入します。
+ */
+ "repositoryUrlDescription": string;
+ /**
+ * リポジトリを公開していない場合、代わりにtarballを提供する必要があります。詳細は.config/example.ymlを参照してください。
+ */
+ "repositoryUrlOrTarballRequired": string;
+ /**
+ * フィードバック
+ */
+ "feedback": string;
+ /**
+ * フィードバックURL
+ */
+ "feedbackUrl": string;
+ /**
* 運営者情報
*/
"impressum": string;
@@ -6814,6 +6846,14 @@ export interface Locale extends ILocale {
*/
"source": string;
/**
+ * オリジナル
+ */
+ "original": string;
+ /**
+ * {name}はオリジナルのMisskeyを改変したバージョンを使用しています。
+ */
+ "thisIsModifiedVersion": ParameterizedString<"name">;
+ /**
* Misskeyを翻訳
*/
"translation": string;
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 5348502425..5993ec80d0 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -991,6 +991,7 @@ neverShow: "今後表示しない"
remindMeLater: "また後で"
didYouLikeMisskey: "Misskeyを気に入っていただけましたか?"
pleaseDonate: "Misskeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします!"
+correspondingSourceIsAvailable: "対応するソースコードは{anchor}から利用可能です。"
roles: "ロール"
role: "ロール"
noRole: "ロールはありません"
@@ -1167,6 +1168,13 @@ hideRepliesToOthersInTimelineAll: "TLに現在フォロー中の人全員の返
confirmShowRepliesAll: "この操作は元に戻せません。本当にTLに現在フォロー中の人全員の返信を含めるようにしますか?"
confirmHideRepliesAll: "この操作は元に戻せません。本当にTLに現在フォロー中の人全員の返信を含めないようにしますか?"
externalServices: "外部サービス"
+sourceCode: "ソースコード"
+sourceCodeIsNotYetProvided: "ソースコードはまだ提供されていません。この問題の修正について管理者に問い合わせてください。"
+repositoryUrl: "リポジトリURL"
+repositoryUrlDescription: "ソースコードが公開されているリポジトリがある場合、そのURLを記入します。Misskeyを現状のまま(ソースコードにいかなる変更も加えずに)使用している場合は https://github.com/misskey-dev/misskey と記入します。"
+repositoryUrlOrTarballRequired: "リポジトリを公開していない場合、代わりにtarballを提供する必要があります。詳細は.config/example.ymlを参照してください。"
+feedback: "フィードバック"
+feedbackUrl: "フィードバックURL"
impressum: "運営者情報"
impressumUrl: "運営者情報URL"
impressumDescription: "ドイツなどの一部の国と地域では表示が義務付けられています(Impressum)。"
@@ -1778,6 +1786,8 @@ _aboutMisskey:
contributors: "コントリビューター"
allContributors: "全てのコントリビューター"
source: "ソースコード"
+ original: "オリジナル"
+ thisIsModifiedVersion: "{name}はオリジナルのMisskeyを改変したバージョンを使用しています。"
translation: "Misskeyを翻訳"
donate: "Misskeyに寄付"
morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰"
diff --git a/packages/backend/migration/1707808106310-MakeRepositoryUrlNullable.js b/packages/backend/migration/1707808106310-MakeRepositoryUrlNullable.js
new file mode 100644
index 0000000000..335b14976c
--- /dev/null
+++ b/packages/backend/migration/1707808106310-MakeRepositoryUrlNullable.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class MakeRepositoryUrlNullable1707808106310 {
+ name = 'MakeRepositoryUrlNullable1707808106310'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" DROP NOT NULL`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET NOT NULL`);
+ }
+}
diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts
index 308da4481b..0ca1fa55c1 100644
--- a/packages/backend/src/config.ts
+++ b/packages/backend/src/config.ts
@@ -57,6 +57,8 @@ type Source = {
scope?: 'local' | 'global' | string[];
};
+ publishTarballInsteadOfProvideRepositoryUrl?: boolean;
+
proxy?: string;
proxySmtp?: string;
proxyBypassHosts?: string[];
@@ -145,6 +147,7 @@ export type Config = {
signToActivityPubGet: boolean | undefined;
version: string;
+ publishTarballInsteadOfProvideRepositoryUrl: boolean;
host: string;
hostname: string;
scheme: string;
@@ -209,6 +212,7 @@ export function loadConfig(): Config {
return {
version,
+ publishTarballInsteadOfProvideRepositoryUrl: !!config.publishTarballInsteadOfProvideRepositoryUrl,
url: url.origin,
port: config.port ?? parseInt(process.env.PORT ?? '', 10),
socket: config.socket,
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index 63503fbe06..6ed0ec6ce5 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -357,9 +357,9 @@ export class MiMeta {
@Column('varchar', {
length: 1024,
default: 'https://github.com/misskey-dev/misskey',
- nullable: false,
+ nullable: true,
})
- public repositoryUrl: string;
+ public repositoryUrl: string | null;
@Column('varchar', {
length: 1024,
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index ef569722e0..88c5907bcc 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -429,7 +429,7 @@ export const meta = {
},
repositoryUrl: {
type: 'string',
- optional: false, nullable: false,
+ optional: false, nullable: true,
},
summalyProxy: {
type: 'string',
diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
index 51075ed3c6..bffceef815 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -104,8 +104,8 @@ export const paramDef = {
swPublicKey: { type: 'string', nullable: true },
swPrivateKey: { type: 'string', nullable: true },
tosUrl: { type: 'string', nullable: true },
- repositoryUrl: { type: 'string' },
- feedbackUrl: { type: 'string' },
+ repositoryUrl: { type: 'string', nullable: true },
+ feedbackUrl: { type: 'string', nullable: true },
impressumUrl: { type: 'string', nullable: true },
privacyPolicyUrl: { type: 'string', nullable: true },
useObjectStorage: { type: 'boolean' },
@@ -402,7 +402,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
}
if (ps.repositoryUrl !== undefined) {
- set.repositoryUrl = ps.repositoryUrl;
+ set.repositoryUrl = URL.canParse(ps.repositoryUrl!) ? ps.repositoryUrl : null;
}
if (ps.feedbackUrl !== undefined) {
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 6bcd7f6b1f..834158baf4 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -37,6 +37,10 @@ export const meta = {
type: 'string',
optional: false, nullable: false,
},
+ providesTarball: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
name: {
type: 'string',
optional: false, nullable: false,
@@ -69,12 +73,12 @@ export const meta = {
},
repositoryUrl: {
type: 'string',
- optional: false, nullable: false,
+ optional: false, nullable: true,
default: 'https://github.com/misskey-dev/misskey',
},
feedbackUrl: {
type: 'string',
- optional: false, nullable: false,
+ optional: false, nullable: true,
default: 'https://github.com/misskey-dev/misskey/issues/new',
},
defaultDarkTheme: {
@@ -352,6 +356,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
maintainerEmail: instance.maintainerEmail,
version: this.config.version,
+ providesTarball: this.config.publishTarballInsteadOfProvideRepositoryUrl,
name: instance.name,
shortName: instance.shortName,
diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts
index afe8e2ac1b..b19d45a35e 100644
--- a/packages/frontend/src/boot/main-boot.ts
+++ b/packages/frontend/src/boot/main-boot.ts
@@ -11,6 +11,7 @@ import { alert, confirm, popup, post, toast } from '@/os.js';
import { useStream } from '@/stream.js';
import * as sound from '@/scripts/sound.js';
import { $i, signout, updateAccount } from '@/account.js';
+import { fetchInstance, instance } from '@/instance.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js';
import { makeHotkey } from '@/scripts/hotkey.js';
import { reactionPicker } from '@/scripts/reaction-picker.js';
@@ -234,6 +235,13 @@ export async function mainBoot() {
}
}
+ fetchInstance().then(() => {
+ const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
+ if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') {
+ popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
+ }
+ });
+
if ('Notification' in window) {
// 許可を得ていなかったらリクエスト
if (Notification.permission === 'default') {
diff --git a/packages/frontend/src/components/MkSourceCodeAvailablePopup.vue b/packages/frontend/src/components/MkSourceCodeAvailablePopup.vue
new file mode 100644
index 0000000000..80f3a6709c
--- /dev/null
+++ b/packages/frontend/src/components/MkSourceCodeAvailablePopup.vue
@@ -0,0 +1,112 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div class="_panel _shadow" :class="$style.root">
+ <div :class="$style.icon">
+ <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-open-source" width="40" height="40" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
+ <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
+ <path d="M12 3a9 9 0 0 1 3.618 17.243l-2.193 -5.602a3 3 0 1 0 -2.849 0l-2.193 5.603a9 9 0 0 1 3.617 -17.244z"/>
+ </svg>
+ </div>
+ <div :class="$style.main">
+ <div :class="$style.title">
+ <I18n :src="i18n.ts.aboutX" tag="span">
+ <template #x>
+ {{ instance.name ?? host }}
+ </template>
+ </I18n>
+ </div>
+ <div :class="$style.text">
+ <I18n :src="i18n.ts._aboutMisskey.thisIsModifiedVersion" tag="span">
+ <template #name>
+ {{ instance.name ?? host }}
+ </template>
+ </I18n>
+ <I18n :src="i18n.ts.correspondingSourceIsAvailable" tag="span">
+ <template #anchor>
+ <MkA to="/about-misskey" class="_link">{{ i18n.ts.aboutMisskey }}</MkA>
+ </template>
+ </I18n>
+ </div>
+ <div class="_buttons">
+ <MkButton @click="close">{{ i18n.ts.gotIt }}</MkButton>
+ </div>
+ </div>
+ <button class="_button" :class="$style.close" @click="close"><i class="ti ti-x"></i></button>
+</div>
+</template>
+
+<script lang="ts" setup>
+import MkButton from '@/components/MkButton.vue';
+import { host } from '@/config.js';
+import { i18n } from '@/i18n.js';
+import { instance } from '@/instance.js';
+import { miLocalStorage } from '@/local-storage.js';
+import * as os from '@/os.js';
+
+const emit = defineEmits<{
+ (ev: 'closed'): void;
+}>();
+
+const zIndex = os.claimZIndex('low');
+
+function close() {
+ miLocalStorage.setItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read', 'true');
+ emit('closed');
+}
+</script>
+
+<style lang="scss" module>
+.root {
+ position: fixed;
+ z-index: v-bind(zIndex);
+ bottom: var(--margin);
+ left: 0;
+ right: 0;
+ margin: auto;
+ box-sizing: border-box;
+ width: calc(100% - (var(--margin) * 2));
+ max-width: 500px;
+ display: flex;
+}
+
+.icon {
+ text-align: center;
+ padding-top: 25px;
+ width: 100px;
+ color: var(--accent);
+}
+@media (max-width: 500px) {
+ .icon {
+ width: 80px;
+ }
+}
+@media (max-width: 450px) {
+ .icon {
+ width: 70px;
+ }
+}
+
+.main {
+ padding: 25px 25px 25px 0;
+ flex: 1;
+}
+
+.close {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ padding: 8px;
+}
+
+.title {
+ font-weight: bold;
+}
+
+.text {
+ margin: 0.7em 0 1em 0;
+}
+</style>
diff --git a/packages/frontend/src/local-storage.ts b/packages/frontend/src/local-storage.ts
index 355715bcc6..3de81c9bb9 100644
--- a/packages/frontend/src/local-storage.ts
+++ b/packages/frontend/src/local-storage.ts
@@ -12,6 +12,7 @@ type Keys =
'latestDonationInfoShownAt' |
'neverShowDonationInfo' |
'neverShowLocalOnlyInfo' |
+ 'modifiedVersionMustProminentlyOfferInAgplV3Section13Read' |
'lastUsed' |
'lang' |
'drafts' |
diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue
index a2ecae3b80..fd97ab97b9 100644
--- a/packages/frontend/src/pages/about-misskey.vue
+++ b/packages/frontend/src/pages/about-misskey.vue
@@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_s">
<FormLink to="https://github.com/misskey-dev/misskey" external>
<template #icon><i class="ti ti-code"></i></template>
- {{ i18n.ts._aboutMisskey.source }}
+ {{ i18n.ts._aboutMisskey.source }} ({{ i18n.ts._aboutMisskey.original }})
<template #suffix>GitHub</template>
</FormLink>
<FormLink to="https://crowdin.com/project/misskey" external>
@@ -46,6 +46,25 @@ SPDX-License-Identifier: AGPL-3.0-only
</FormLink>
</div>
</FormSection>
+ <FormSection v-if="instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey'">
+ <div class="_gaps_s">
+ <MkInfo>
+ {{ i18n.tsx._aboutMisskey.thisIsModifiedVersion({ name: instance.name }) }}
+ </MkInfo>
+ <FormLink v-if="instance.repositoryUrl" :to="instance.repositoryUrl" external>
+ <template #icon><i class="ti ti-code"></i></template>
+ {{ i18n.ts._aboutMisskey.source }}
+ </FormLink>
+ <FormLink v-if="instance.providesTarball" :to="`/tarball/misskey-${version}.tar.gz`" external>
+ <template #icon><i class="ti ti-download"></i></template>
+ {{ i18n.ts._aboutMisskey.source }}
+ <template #suffix>Tarball</template>
+ </FormLink>
+ <MkInfo v-if="!instance.repositoryUrl && !instance.providesTarball" warn>
+ {{ i18n.ts.sourceCodeIsNotYetProvided }}
+ </MkInfo>
+ </div>
+ </FormSection>
<FormSection>
<template #label>{{ i18n.ts._aboutMisskey.projectMembers }}</template>
<div :class="$style.contributors">
@@ -118,9 +137,10 @@ import { version } from '@/config.js';
import FormLink from '@/components/form/link.vue';
import FormSection from '@/components/form/section.vue';
import MkButton from '@/components/MkButton.vue';
-import MkLink from '@/components/MkLink.vue';
+import MkInfo from '@/components/MkInfo.vue';
import { physics } from '@/scripts/physics.js';
import { i18n } from '@/i18n.js';
+import { instance } from '@/instance.js';
import { defaultStore } from '@/store.js';
import * as os from '@/os.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue
index f99eb9c577..324d1c11de 100644
--- a/packages/frontend/src/pages/about.vue
+++ b/packages/frontend/src/pages/about.vue
@@ -31,7 +31,17 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkKeyValue>
<div v-html="i18n.tsx.poweredByMisskeyDescription({ name: instance.name ?? host })">
</div>
- <FormLink to="/about-misskey">{{ i18n.ts.aboutMisskey }}</FormLink>
+ <FormLink to="/about-misskey">
+ <template #icon><i class="ti ti-info-circle"></i></template>
+ {{ i18n.ts.aboutMisskey }}
+ </FormLink>
+ <FormLink v-if="instance.repositoryUrl || instance.providesTarball" :to="instance.repositoryUrl || `/tarball/misskey-${version}.tar.gz`" external>
+ <template #icon><i class="ti ti-code"></i></template>
+ {{ i18n.ts.sourceCode }}
+ </FormLink>
+ <MkInfo v-else warn>
+ {{ i18n.ts.sourceCodeIsNotYetProvided }}
+ </MkInfo>
</div>
</FormSection>
@@ -47,17 +57,33 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #value>{{ instance.maintainerEmail }}</template>
</MkKeyValue>
</FormSplit>
- <FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>{{ i18n.ts.impressum }}</FormLink>
+ <FormLink v-if="instance.impressumUrl" :to="instance.impressumUrl" external>
+ <template #icon><i class="ti ti-user-shield"></i></template>
+ {{ i18n.ts.impressum }}
+ </FormLink>
<div class="_gaps_s">
<MkFolder v-if="instance.serverRules.length > 0">
- <template #label>{{ i18n.ts.serverRules }}</template>
+ <template #label>
+ <i class="ti ti-checkup-list"></i>
+ {{ i18n.ts.serverRules }}
+ </template>
<ol class="_gaps_s" :class="$style.rules">
- <li v-for="item, index in instance.serverRules" :key="index" :class="$style.rule"><div :class="$style.ruleText" v-html="item"></div></li>
+ <li v-for="(item, index) in instance.serverRules" :key="index" :class="$style.rule"><div :class="$style.ruleText" v-html="item"></div></li>
</ol>
</MkFolder>
- <FormLink v-if="instance.tosUrl" :to="instance.tosUrl" external>{{ i18n.ts.termsOfService }}</FormLink>
- <FormLink v-if="instance.privacyPolicyUrl" :to="instance.privacyPolicyUrl" external>{{ i18n.ts.privacyPolicy }}</FormLink>
+ <FormLink v-if="instance.tosUrl" :to="instance.tosUrl" external>
+ <template #icon><i class="ti ti-license"></i></template>
+ {{ i18n.ts.termsOfService }}
+ </FormLink>
+ <FormLink v-if="instance.privacyPolicyUrl" :to="instance.privacyPolicyUrl" external>
+ <template #icon><i class="ti ti-shield-lock"></i></template>
+ {{ i18n.ts.privacyPolicy }}
+ </FormLink>
+ <FormLink v-if="instance.feedbackUrl" :to="instance.feedbackUrl" external>
+ <template #icon><i class="ti ti-message"></i></template>
+ {{ i18n.ts.feedback }}
+ </FormLink>
</div>
</div>
</FormSection>
@@ -86,7 +112,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<FormLink :to="`/.well-known/nodeinfo`" external>nodeinfo</FormLink>
<FormLink :to="`/robots.txt`" external>robots.txt</FormLink>
<FormLink :to="`/manifest.json`" external>manifest.json</FormLink>
- <FormLink :to="`/tarball/misskey-${version}.tar.gz`" external>source code</FormLink>
</div>
</FormSection>
</div>
@@ -116,6 +141,7 @@ import FormSuspense from '@/components/form/suspense.vue';
import FormSplit from '@/components/form/split.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
+import MkInfo from '@/components/MkInfo.vue';
import MkInstanceStats from '@/components/MkInstanceStats.vue';
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
diff --git a/packages/frontend/src/pages/admin/branding.vue b/packages/frontend/src/pages/admin/branding.vue
index 4ac2011aaf..2b559f92c9 100644
--- a/packages/frontend/src/pages/admin/branding.vue
+++ b/packages/frontend/src/pages/admin/branding.vue
@@ -76,6 +76,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
</MkTextarea>
+ <MkInput v-model="repositoryUrl" type="url">
+ <template #prefix><i class="ti ti-link"></i></template>
+ <template #label>{{ i18n.ts.repositoryUrl }}</template>
+ </MkInput>
+
+ <MkInput v-model="feedbackUrl" type="url">
+ <template #prefix><i class="ti ti-link"></i></template>
+ <template #label>{{ i18n.ts.feedbackUrl }}</template>
+ </MkInput>
+
<MkTextarea v-model="manifestJsonOverride">
<template #label>{{ i18n.ts._serverSettings.manifestJsonOverride }}</template>
</MkTextarea>
@@ -120,6 +130,8 @@ const defaultDarkTheme = ref<string | null>(null);
const serverErrorImageUrl = ref<string | null>(null);
const infoImageUrl = ref<string | null>(null);
const notFoundImageUrl = ref<string | null>(null);
+const repositoryUrl = ref<string | null>(null);
+const feedbackUrl = ref<string | null>(null);
const manifestJsonOverride = ref<string>('{}');
async function init() {
@@ -135,6 +147,8 @@ async function init() {
serverErrorImageUrl.value = meta.serverErrorImageUrl;
infoImageUrl.value = meta.infoImageUrl;
notFoundImageUrl.value = meta.notFoundImageUrl;
+ repositoryUrl.value = meta.repositoryUrl;
+ feedbackUrl.value = meta.feedbackUrl;
manifestJsonOverride.value = meta.manifestJsonOverride === '' ? '{}' : JSON.stringify(JSON.parse(meta.manifestJsonOverride), null, '\t');
}
@@ -151,6 +165,8 @@ function save() {
infoImageUrl: infoImageUrl.value === '' ? null : infoImageUrl.value,
notFoundImageUrl: notFoundImageUrl.value === '' ? null : notFoundImageUrl.value,
serverErrorImageUrl: serverErrorImageUrl.value === '' ? null : serverErrorImageUrl.value,
+ repositoryUrl: repositoryUrl.value === '' ? null : repositoryUrl.value,
+ feedbackUrl: feedbackUrl.value === '' ? null : feedbackUrl.value,
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
}).then(() => {
fetchInstance();
diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue
index 8af9deae62..c505d70aa9 100644
--- a/packages/frontend/src/pages/admin/settings.vue
+++ b/packages/frontend/src/pages/admin/settings.vue
@@ -34,6 +34,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
</FormSplit>
+ <MkInput v-model="repositoryUrl" type="url">
+ <template #label>{{ i18n.ts.repositoryUrl }}</template>
+ <template #prefix><i class="ti ti-link"></i></template>
+ <template #caption>{{ i18n.ts.repositoryUrlDescription }}</template>
+ </MkInput>
+
+ <MkInfo v-if="!instance.providesTarball && !repositoryUrl" warn>
+ {{ i18n.ts.repositoryUrlOrTarballRequired }}
+ </MkInfo>
+
<MkInput v-model="impressumUrl" type="url">
<template #label>{{ i18n.ts.impressumUrl }}</template>
<template #prefix><i class="ti ti-link"></i></template>
@@ -159,7 +169,7 @@ import FormSplit from '@/components/form/split.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
-import { fetchInstance } from '@/instance.js';
+import { fetchInstance, instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
@@ -169,6 +179,7 @@ const shortName = ref<string | null>(null);
const description = ref<string | null>(null);
const maintainerName = ref<string | null>(null);
const maintainerEmail = ref<string | null>(null);
+const repositoryUrl = ref<string | null>(null);
const impressumUrl = ref<string | null>(null);
const pinnedUsers = ref<string>('');
const cacheRemoteFiles = ref<boolean>(false);
@@ -191,6 +202,7 @@ async function init(): Promise<void> {
description.value = meta.description;
maintainerName.value = meta.maintainerName;
maintainerEmail.value = meta.maintainerEmail;
+ repositoryUrl.value = meta.repositoryUrl;
impressumUrl.value = meta.impressumUrl;
pinnedUsers.value = meta.pinnedUsers.join('\n');
cacheRemoteFiles.value = meta.cacheRemoteFiles;
@@ -214,6 +226,7 @@ async function save(): void {
description: description.value,
maintainerName: maintainerName.value,
maintainerEmail: maintainerEmail.value,
+ repositoryUrl: repositoryUrl.value,
impressumUrl: impressumUrl.value,
pinnedUsers: pinnedUsers.value.split('\n'),
cacheRemoteFiles: cacheRemoteFiles.value,
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index ad3a9a7c66..d0d8573b40 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -4845,7 +4845,7 @@ export type operations = {
shortName: string | null;
objectStorageS3ForcePathStyle: boolean;
privacyPolicyUrl: string | null;
- repositoryUrl: string;
+ repositoryUrl: string | null;
summalyProxy: string | null;
themeColor: string | null;
tosUrl: string | null;
@@ -8757,8 +8757,8 @@ export type operations = {
swPublicKey?: string | null;
swPrivateKey?: string | null;
tosUrl?: string | null;
- repositoryUrl?: string;
- feedbackUrl?: string;
+ repositoryUrl?: string | null;
+ feedbackUrl?: string | null;
impressumUrl?: string | null;
privacyPolicyUrl?: string | null;
useObjectStorage?: boolean;
@@ -19450,6 +19450,7 @@ export type operations = {
maintainerName: string | null;
maintainerEmail: string | null;
version: string;
+ providesTarball: boolean;
name: string;
shortName: string | null;
/**
@@ -19461,9 +19462,9 @@ export type operations = {
langs: string[];
tosUrl: string | null;
/** @default https://github.com/misskey-dev/misskey */
- repositoryUrl: string;
+ repositoryUrl: string | null;
/** @default https://github.com/misskey-dev/misskey/issues/new */
- feedbackUrl: string;
+ feedbackUrl: string | null;
defaultDarkTheme: string | null;
defaultLightTheme: string | null;
disableRegistration: boolean;
diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs
index bafb1da5d9..e7684d7cc9 100644
--- a/scripts/build-assets.mjs
+++ b/scripts/build-assets.mjs
@@ -5,7 +5,9 @@
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
+import { fileURLToPath } from 'node:url';
import cssnano from 'cssnano';
+import * as yaml from 'js-yaml';
import postcss from 'postcss';
import * as terser from 'terser';
@@ -14,8 +16,19 @@ import generateDTS from '../locales/generateDTS.js';
import meta from '../package.json' assert { type: "json" };
import buildTarball from './tarball.mjs';
+const configDir = fileURLToPath(new URL('../.config', import.meta.url));
+const configPath = process.env.MISSKEY_CONFIG_YML
+ ? path.resolve(configDir, process.env.MISSKEY_CONFIG_YML)
+ : process.env.NODE_ENV === 'test'
+ ? path.resolve(configDir, 'test.yml')
+ : path.resolve(configDir, 'default.yml');
+
let locales = buildLocales();
+async function loadConfig() {
+ return fs.readFile(configPath, 'utf-8').then(data => yaml.load(data)).catch(() => null);
+}
+
async function copyFrontendFonts() {
await fs.cp('./packages/frontend/node_modules/three/examples/fonts', './built/_frontend_dist_/fonts', { dereference: true, recursive: true });
}
@@ -78,7 +91,7 @@ async function build() {
copyBackendViews(),
buildBackendScript(),
buildBackendStyle(),
- buildTarball(),
+ loadConfig().then(config => config?.publishTarballInsteadOfProvideRepositoryUrl && buildTarball()),
]);
}