reCAPTCHAの設定をDBに保存するように
This commit is contained in:
parent
d5ab6b41c9
commit
a6f8327aa2
10 changed files with 99 additions and 36 deletions
|
@ -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)
|
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.
|
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
|
*(optional)* Generating VAPID keys
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
If you want to enable ServiceWorker, you need to generate VAPID keys:
|
If you want to enable ServiceWorker, you need to generate VAPID keys:
|
||||||
|
|
|
@ -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)を確認
|
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の依存パッケージをインストール
|
5. `npm install` Misskeyの依存パッケージをインストール
|
||||||
|
|
||||||
*(オプション)* reCAPTCHAトークン
|
|
||||||
----------------------------------------------------------------
|
|
||||||
reCAPTCHAを有効にする場合、reCAPTCHAトークンを取得する必要があります。
|
|
||||||
https://www.google.com/recaptcha/intro/ にアクセスしてトークンを取得してください。
|
|
||||||
|
|
||||||
*(オプション)* VAPIDキーペアの生成
|
*(オプション)* VAPIDキーペアの生成
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります:
|
ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります:
|
||||||
|
|
|
@ -1085,6 +1085,11 @@ admin/views/instance.vue:
|
||||||
local-drive-capacity-mb: "ローカルユーザーひとりあたりのドライブ容量"
|
local-drive-capacity-mb: "ローカルユーザーひとりあたりのドライブ容量"
|
||||||
remote-drive-capacity-mb: "リモートユーザーひとりあたりのドライブ容量"
|
remote-drive-capacity-mb: "リモートユーザーひとりあたりのドライブ容量"
|
||||||
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: "投稿の最大文字数"
|
max-note-text-length: "投稿の最大文字数"
|
||||||
disable-registration: "ユーザー登録の受付を停止する"
|
disable-registration: "ユーザー登録の受付を停止する"
|
||||||
disable-local-timeline: "ローカルタイムラインを無効にする"
|
disable-local-timeline: "ローカルタイムラインを無効にする"
|
||||||
|
|
|
@ -16,6 +16,13 @@
|
||||||
<ui-input v-model="localDriveCapacityMb">%i18n:@local-drive-capacity-mb%<span slot="desc">%i18n:@mb%</span><span slot="suffix">MB</span></ui-input>
|
<ui-input v-model="localDriveCapacityMb">%i18n:@local-drive-capacity-mb%<span slot="desc">%i18n:@mb%</span><span slot="suffix">MB</span></ui-input>
|
||||||
<ui-input v-model="remoteDriveCapacityMb" :disabled="!cacheRemoteFiles">%i18n:@remote-drive-capacity-mb%<span slot="desc">%i18n:@mb%</span><span slot="suffix">MB</span></ui-input>
|
<ui-input v-model="remoteDriveCapacityMb" :disabled="!cacheRemoteFiles">%i18n:@remote-drive-capacity-mb%<span slot="desc">%i18n:@mb%</span><span slot="suffix">MB</span></ui-input>
|
||||||
</section>
|
</section>
|
||||||
|
<section class="fit-bottom">
|
||||||
|
<header><fa icon="shield-alt"/> %i18n:@recaptcha-config%</header>
|
||||||
|
<ui-switch v-model="enableRecaptcha">%i18n:@enable-recaptcha%</ui-switch>
|
||||||
|
<ui-info>%i18n:@recaptcha-info%</ui-info>
|
||||||
|
<ui-input v-model="recaptchaSiteKey" :disabled="!enableRecaptcha"><i slot="icon"><fa icon="key"/></i>%i18n:@recaptcha-site-key%</ui-input>
|
||||||
|
<ui-input v-model="recaptchaSecretKey" :disabled="!enableRecaptcha"><i slot="icon"><fa icon="key"/></i>%i18n:@recaptcha-secret-key%</ui-input>
|
||||||
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<ui-button @click="updateMeta">%i18n:@save%</ui-button>
|
<ui-button @click="updateMeta">%i18n:@save%</ui-button>
|
||||||
</section>
|
</section>
|
||||||
|
@ -54,6 +61,9 @@ export default Vue.extend({
|
||||||
localDriveCapacityMb: null,
|
localDriveCapacityMb: null,
|
||||||
remoteDriveCapacityMb: null,
|
remoteDriveCapacityMb: null,
|
||||||
maxNoteTextLength: null,
|
maxNoteTextLength: null,
|
||||||
|
enableRecaptcha: false,
|
||||||
|
recaptchaSiteKey: null,
|
||||||
|
recaptchaSecretKey: null,
|
||||||
inviteCode: null,
|
inviteCode: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -67,6 +77,9 @@ export default Vue.extend({
|
||||||
this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
|
this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
|
||||||
this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
|
this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
|
||||||
this.maxNoteTextLength = meta.maxNoteTextLength;
|
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,
|
cacheRemoteFiles: this.cacheRemoteFiles,
|
||||||
localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
|
localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
|
||||||
remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 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(() => {
|
}).then(() => {
|
||||||
this.$swal({
|
this.$swal({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@password-not-matched%</p>
|
<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@password-not-matched%</p>
|
||||||
</div>
|
</div>
|
||||||
</ui-input>
|
</ui-input>
|
||||||
<div v-if="meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div>
|
<div v-if="meta.recaptchaSiteKey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSiteKey" style="margin: 16px 0;"></div>
|
||||||
<ui-button type="submit">%i18n:@create%</ui-button>
|
<ui-button type="submit">%i18n:@create%</ui-button>
|
||||||
</template>
|
</template>
|
||||||
</form>
|
</form>
|
||||||
|
@ -130,7 +130,7 @@ export default Vue.extend({
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
invitationCode: this.invitationCode,
|
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(() => {
|
}, true).then(() => {
|
||||||
(this as any).api('signin', {
|
(this as any).api('signin', {
|
||||||
username: this.username,
|
username: this.username,
|
||||||
|
@ -141,7 +141,7 @@ export default Vue.extend({
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
alert('%i18n:@some-error%');
|
alert('%i18n:@some-error%');
|
||||||
|
|
||||||
if (this.meta.recaptchaSitekey != null) {
|
if (this.meta.recaptchaSiteKey != null) {
|
||||||
(window as any).grecaptcha.reset();
|
(window as any).grecaptcha.reset();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -40,11 +40,6 @@ export type Source = {
|
||||||
port: number;
|
port: number;
|
||||||
pass: string;
|
pass: string;
|
||||||
};
|
};
|
||||||
recaptcha?: {
|
|
||||||
site_key: string;
|
|
||||||
secret_key: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
drive?: {
|
drive?: {
|
||||||
storage: string;
|
storage: string;
|
||||||
bucket?: string;
|
bucket?: string;
|
||||||
|
|
|
@ -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 = {
|
export type IMeta = {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
@ -79,6 +92,10 @@ export type IMeta = {
|
||||||
|
|
||||||
cacheRemoteFiles?: boolean;
|
cacheRemoteFiles?: boolean;
|
||||||
|
|
||||||
|
enableRecaptcha?: boolean;
|
||||||
|
recaptchaSiteKey?: string;
|
||||||
|
recaptchaSecretKey?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drive capacity of a local user (MB)
|
* Drive capacity of a local user (MB)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -88,6 +88,27 @@ export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
'ja-JP': 'リモートのファイルをキャッシュするか否か'
|
'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;
|
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({}, {
|
await Meta.update({}, {
|
||||||
$set: set
|
$set: set
|
||||||
}, { upsert: true });
|
}, { upsert: true });
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
res({
|
const response: any = {
|
||||||
maintainer: config.maintainer,
|
maintainer: config.maintainer,
|
||||||
|
|
||||||
version: pkg.version,
|
version: pkg.version,
|
||||||
|
@ -60,24 +60,32 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
|
||||||
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
|
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
|
||||||
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
|
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
|
||||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
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,
|
swPublickey: config.sw ? config.sw.public_key : null,
|
||||||
hidedTags: (me && me.isAdmin) ? instance.hidedTags : undefined,
|
|
||||||
bannerUrl: instance.bannerUrl,
|
bannerUrl: instance.bannerUrl,
|
||||||
maxNoteTextLength: instance.maxNoteTextLength,
|
maxNoteTextLength: instance.maxNoteTextLength,
|
||||||
|
|
||||||
emojis: emojis,
|
emojis: emojis,
|
||||||
|
};
|
||||||
|
|
||||||
features: ps.detail ? {
|
if (ps.detail) {
|
||||||
|
response.features = {
|
||||||
registration: !instance.disableRegistration,
|
registration: !instance.disableRegistration,
|
||||||
localTimeLine: !instance.disableLocalTimeline,
|
localTimeLine: !instance.disableLocalTimeline,
|
||||||
elasticsearch: config.elasticsearch ? true : false,
|
elasticsearch: config.elasticsearch ? true : false,
|
||||||
recaptcha: config.recaptcha ? true : false,
|
recaptcha: instance.enableRecaptcha,
|
||||||
objectStorage: config.drive && config.drive.storage === 'minio',
|
objectStorage: config.drive && config.drive.storage === 'minio',
|
||||||
twitter: config.twitter ? true : false,
|
twitter: config.twitter ? true : false,
|
||||||
github: config.github ? true : false,
|
github: config.github ? true : false,
|
||||||
serviceWorker: config.sw ? true : false,
|
serviceWorker: config.sw ? true : false,
|
||||||
userRecommendation: config.user_recommendation ? config.user_recommendation : {}
|
userRecommendation: config.user_recommendation ? config.user_recommendation : {}
|
||||||
} : undefined
|
};
|
||||||
});
|
}
|
||||||
|
|
||||||
|
if (me && me.isAdmin) {
|
||||||
|
response.hidedTags = instance.hidedTags;
|
||||||
|
response.recaptchaSecretKey = instance.recaptchaSecretKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
res(response);
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import * as Koa from 'koa';
|
import * as Koa from 'koa';
|
||||||
import * as bcrypt from 'bcryptjs';
|
import * as bcrypt from 'bcryptjs';
|
||||||
import { generate as generateKeypair } from '../../../crypto_key';
|
import { generate as generateKeypair } from '../../../crypto_key';
|
||||||
const recaptcha = require('recaptcha-promise');
|
|
||||||
import User, { IUser, validateUsername, validatePassword, pack } from '../../../models/user';
|
import User, { IUser, validateUsername, validatePassword, pack } from '../../../models/user';
|
||||||
import generateUserToken from '../common/generate-native-user-token';
|
import generateUserToken from '../common/generate-native-user-token';
|
||||||
import config from '../../../config';
|
import config from '../../../config';
|
||||||
|
@ -10,18 +9,20 @@ import RegistrationTicket from '../../../models/registration-tickets';
|
||||||
import usersChart from '../../../chart/users';
|
import usersChart from '../../../chart/users';
|
||||||
import fetchMeta from '../../../misc/fetch-meta';
|
import fetchMeta from '../../../misc/fetch-meta';
|
||||||
|
|
||||||
if (config.recaptcha) {
|
|
||||||
recaptcha.init({
|
|
||||||
secret_key: config.recaptcha.secret_key
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async (ctx: Koa.Context) => {
|
export default async (ctx: Koa.Context) => {
|
||||||
const body = ctx.request.body as any;
|
const body = ctx.request.body as any;
|
||||||
|
|
||||||
|
const instance = await fetchMeta();
|
||||||
|
|
||||||
|
const recaptcha = require('recaptcha-promise');
|
||||||
|
|
||||||
// Verify recaptcha
|
// 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']);
|
const success = await recaptcha(body['g-recaptcha-response']);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -34,8 +35,6 @@ export default async (ctx: Koa.Context) => {
|
||||||
const password = body['password'];
|
const password = body['password'];
|
||||||
const invitationCode = body['invitationCode'];
|
const invitationCode = body['invitationCode'];
|
||||||
|
|
||||||
const instance = await fetchMeta();
|
|
||||||
|
|
||||||
if (instance && instance.disableRegistration) {
|
if (instance && instance.disableRegistration) {
|
||||||
if (invitationCode == null || typeof invitationCode != 'string') {
|
if (invitationCode == null || typeof invitationCode != 'string') {
|
||||||
ctx.status = 400;
|
ctx.status = 400;
|
||||||
|
|
Loading…
Reference in a new issue