diff --git a/docs/setup.en.md b/docs/setup.en.md
index 72da57a9aa..83392d0d9a 100644
--- a/docs/setup.en.md
+++ b/docs/setup.en.md
@@ -47,11 +47,6 @@ In root :
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
5. `npm install` Install misskey dependencies.
-*(optional)* reCAPTCHA tokens
-----------------------------------------------------------------
-If you want to enable reCAPTCHA, you need to generate reCAPTCHA tokens:
-Please visit https://www.google.com/recaptcha/intro/ and generate keys.
-
*(optional)* Generating VAPID keys
----------------------------------------------------------------
If you want to enable ServiceWorker, you need to generate VAPID keys:
diff --git a/docs/setup.ja.md b/docs/setup.ja.md
index 606857219a..79be1fb881 100644
--- a/docs/setup.ja.md
+++ b/docs/setup.ja.md
@@ -53,11 +53,6 @@ adduser --disabled-password --disabled-login misskey
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
5. `npm install` Misskeyの依存パッケージをインストール
-*(オプション)* reCAPTCHAトークン
-----------------------------------------------------------------
-reCAPTCHAを有効にする場合、reCAPTCHAトークンを取得する必要があります。
-https://www.google.com/recaptcha/intro/ にアクセスしてトークンを取得してください。
-
*(オプション)* VAPIDキーペアの生成
----------------------------------------------------------------
ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります:
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 22e6212607..840dce5735 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1085,6 +1085,11 @@ admin/views/instance.vue:
local-drive-capacity-mb: "ローカルユーザーひとりあたりのドライブ容量"
remote-drive-capacity-mb: "リモートユーザーひとりあたりのドライブ容量"
mb: "メガバイト単位"
+ recaptcha-config: "reCAPTCHAの設定"
+ recaptcha-info: "reCAPTCHAを有効にする場合、reCAPTCHAトークンを取得する必要があります。https://www.google.com/recaptcha/intro/ にアクセスしてトークンを取得してください。"
+ enable-recaptcha: "reCAPTCHAを有効にする"
+ recaptcha-site-key: "reCAPTCHA site key"
+ recaptcha-secret-key: "reCAPTCHA secret key"
max-note-text-length: "投稿の最大文字数"
disable-registration: "ユーザー登録の受付を停止する"
disable-local-timeline: "ローカルタイムラインを無効にする"
diff --git a/src/client/app/admin/views/instance.vue b/src/client/app/admin/views/instance.vue
index 050fb6617d..47ab9e6159 100644
--- a/src/client/app/admin/views/instance.vue
+++ b/src/client/app/admin/views/instance.vue
@@ -16,6 +16,13 @@
%i18n:@local-drive-capacity-mb%%i18n:@mb%MB
%i18n:@remote-drive-capacity-mb%%i18n:@mb%MB
+
+
+ %i18n:@enable-recaptcha%
+ %i18n:@recaptcha-info%
+ %i18n:@recaptcha-site-key%
+ %i18n:@recaptcha-secret-key%
+
@@ -54,6 +61,9 @@ export default Vue.extend({
localDriveCapacityMb: null,
remoteDriveCapacityMb: null,
maxNoteTextLength: null,
+ enableRecaptcha: false,
+ recaptchaSiteKey: null,
+ recaptchaSecretKey: null,
inviteCode: null,
};
},
@@ -67,6 +77,9 @@ export default Vue.extend({
this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
this.maxNoteTextLength = meta.maxNoteTextLength;
+ this.enableRecaptcha = meta.enableRecaptcha;
+ this.recaptchaSiteKey = meta.recaptchaSiteKey;
+ this.recaptchaSecretKey = meta.recaptchaSecretKey;
});
},
@@ -92,7 +105,10 @@ export default Vue.extend({
cacheRemoteFiles: this.cacheRemoteFiles,
localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
- maxNoteTextLength: parseInt(this.maxNoteTextLength, 10)
+ maxNoteTextLength: parseInt(this.maxNoteTextLength, 10),
+ enableRecaptcha: this.enableRecaptcha,
+ recaptchaSiteKey: this.recaptchaSiteKey,
+ recaptchaSecretKey: this.recaptchaSecretKey
}).then(() => {
this.$swal({
type: 'success',
diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue
index fa26eabc91..91a09e14fb 100644
--- a/src/client/app/common/views/components/signup.vue
+++ b/src/client/app/common/views/components/signup.vue
@@ -35,7 +35,7 @@
%i18n:@password-not-matched%
-
+
%i18n:@create%
@@ -130,7 +130,7 @@ export default Vue.extend({
username: this.username,
password: this.password,
invitationCode: this.invitationCode,
- 'g-recaptcha-response': this.meta.recaptchaSitekey != null ? (window as any).grecaptcha.getResponse() : null
+ 'g-recaptcha-response': this.meta.recaptchaSiteKey != null ? (window as any).grecaptcha.getResponse() : null
}, true).then(() => {
(this as any).api('signin', {
username: this.username,
@@ -141,7 +141,7 @@ export default Vue.extend({
}).catch(() => {
alert('%i18n:@some-error%');
- if (this.meta.recaptchaSitekey != null) {
+ if (this.meta.recaptchaSiteKey != null) {
(window as any).grecaptcha.reset();
}
});
diff --git a/src/config/types.ts b/src/config/types.ts
index ff19af27c0..07d2ec318f 100644
--- a/src/config/types.ts
+++ b/src/config/types.ts
@@ -40,11 +40,6 @@ export type Source = {
port: number;
pass: string;
};
- recaptcha?: {
- site_key: string;
- secret_key: string;
- };
-
drive?: {
storage: string;
bucket?: string;
diff --git a/src/models/meta.ts b/src/models/meta.ts
index 073be7de82..3eb73681ac 100644
--- a/src/models/meta.ts
+++ b/src/models/meta.ts
@@ -61,6 +61,19 @@ if ((config as any).preventCacheRemoteFiles) {
}
});
}
+if ((config as any).recaptcha) {
+ Meta.findOne({}).then(m => {
+ if (m != null && m.enableRecaptcha == null) {
+ Meta.update({}, {
+ $set: {
+ enableRecaptcha: (config as any).recaptcha != null,
+ recaptchaSiteKey: (config as any).recaptcha.site_key,
+ recaptchaSecretKey: (config as any).recaptcha.secret_key,
+ }
+ });
+ }
+ });
+}
export type IMeta = {
name?: string;
@@ -79,6 +92,10 @@ export type IMeta = {
cacheRemoteFiles?: boolean;
+ enableRecaptcha?: boolean;
+ recaptchaSiteKey?: string;
+ recaptchaSecretKey?: string;
+
/**
* Drive capacity of a local user (MB)
*/
diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts
index b4b2b231ab..85266b47cf 100644
--- a/src/server/api/endpoints/admin/update-meta.ts
+++ b/src/server/api/endpoints/admin/update-meta.ts
@@ -88,6 +88,27 @@ export const meta = {
desc: {
'ja-JP': 'リモートのファイルをキャッシュするか否か'
}
+ },
+
+ enableRecaptcha: {
+ validator: $.bool.optional,
+ desc: {
+ 'ja-JP': 'reCAPTCHAを使用するか否か'
+ }
+ },
+
+ recaptchaSiteKey: {
+ validator: $.str.optional,
+ desc: {
+ 'ja-JP': 'reCAPTCHA site key'
+ }
+ },
+
+ recaptchaSecretKey: {
+ validator: $.str.optional,
+ desc: {
+ 'ja-JP': 'reCAPTCHA secret key'
+ }
}
}
};
@@ -139,6 +160,18 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
set.cacheRemoteFiles = ps.cacheRemoteFiles;
}
+ if (ps.enableRecaptcha !== undefined) {
+ set.enableRecaptcha = ps.enableRecaptcha;
+ }
+
+ if (ps.recaptchaSiteKey !== undefined) {
+ set.recaptchaSiteKey = ps.recaptchaSiteKey;
+ }
+
+ if (ps.recaptchaSecretKey !== undefined) {
+ set.recaptchaSecretKey = ps.recaptchaSecretKey;
+ }
+
await Meta.update({}, {
$set: set
}, { upsert: true });
diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts
index e3d3ad520f..3ed225cc5f 100644
--- a/src/server/api/endpoints/meta.ts
+++ b/src/server/api/endpoints/meta.ts
@@ -35,7 +35,7 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
}
});
- res({
+ const response: any = {
maintainer: config.maintainer,
version: pkg.version,
@@ -60,24 +60,32 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
cacheRemoteFiles: instance.cacheRemoteFiles,
- recaptchaSitekey: config.recaptcha ? config.recaptcha.site_key : null,
+ recaptchaSiteKey: instance.enableRecaptcha ? instance.recaptchaSiteKey : null,
swPublickey: config.sw ? config.sw.public_key : null,
- hidedTags: (me && me.isAdmin) ? instance.hidedTags : undefined,
bannerUrl: instance.bannerUrl,
maxNoteTextLength: instance.maxNoteTextLength,
emojis: emojis,
+ };
- features: ps.detail ? {
+ if (ps.detail) {
+ response.features = {
registration: !instance.disableRegistration,
localTimeLine: !instance.disableLocalTimeline,
elasticsearch: config.elasticsearch ? true : false,
- recaptcha: config.recaptcha ? true : false,
+ recaptcha: instance.enableRecaptcha,
objectStorage: config.drive && config.drive.storage === 'minio',
twitter: config.twitter ? true : false,
github: config.github ? true : false,
serviceWorker: config.sw ? true : false,
userRecommendation: config.user_recommendation ? config.user_recommendation : {}
- } : undefined
- });
+ };
+ }
+
+ if (me && me.isAdmin) {
+ response.hidedTags = instance.hidedTags;
+ response.recaptchaSecretKey = instance.recaptchaSecretKey;
+ }
+
+ res(response);
}));
diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts
index eefffd8554..3a367ff119 100644
--- a/src/server/api/private/signup.ts
+++ b/src/server/api/private/signup.ts
@@ -1,7 +1,6 @@
import * as Koa from 'koa';
import * as bcrypt from 'bcryptjs';
import { generate as generateKeypair } from '../../../crypto_key';
-const recaptcha = require('recaptcha-promise');
import User, { IUser, validateUsername, validatePassword, pack } from '../../../models/user';
import generateUserToken from '../common/generate-native-user-token';
import config from '../../../config';
@@ -10,18 +9,20 @@ import RegistrationTicket from '../../../models/registration-tickets';
import usersChart from '../../../chart/users';
import fetchMeta from '../../../misc/fetch-meta';
-if (config.recaptcha) {
- recaptcha.init({
- secret_key: config.recaptcha.secret_key
- });
-}
-
export default async (ctx: Koa.Context) => {
const body = ctx.request.body as any;
+ const instance = await fetchMeta();
+
+ const recaptcha = require('recaptcha-promise');
+
// Verify recaptcha
// ただしテスト時はこの機構は障害となるため無効にする
- if (process.env.NODE_ENV !== 'test' && config.recaptcha != null) {
+ if (process.env.NODE_ENV !== 'test' && instance.enableRecaptcha) {
+ recaptcha.init({
+ secret_key: instance.recaptchaSecretKey
+ });
+
const success = await recaptcha(body['g-recaptcha-response']);
if (!success) {
@@ -34,8 +35,6 @@ export default async (ctx: Koa.Context) => {
const password = body['password'];
const invitationCode = body['invitationCode'];
- const instance = await fetchMeta();
-
if (instance && instance.disableRegistration) {
if (invitationCode == null || typeof invitationCode != 'string') {
ctx.status = 400;