summaryrefslogtreecommitdiff
path: root/src/server/api/private
diff options
context:
space:
mode:
authorAkihiko Odaki <nekomanma@pixiv.co.jp>2018-03-29 01:20:40 +0900
committerAkihiko Odaki <nekomanma@pixiv.co.jp>2018-03-29 01:54:41 +0900
commit90f8fe7e538bb7e52d2558152a0390e693f39b11 (patch)
tree0f830887053c8f352b1cd0c13ca715fd14c1f030 /src/server/api/private
parentImplement remote account resolution (diff)
downloadsharkey-90f8fe7e538bb7e52d2558152a0390e693f39b11.tar.gz
sharkey-90f8fe7e538bb7e52d2558152a0390e693f39b11.tar.bz2
sharkey-90f8fe7e538bb7e52d2558152a0390e693f39b11.zip
Introduce processor
Diffstat (limited to 'src/server/api/private')
-rw-r--r--src/server/api/private/signin.ts91
-rw-r--r--src/server/api/private/signup.ts165
2 files changed, 256 insertions, 0 deletions
diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts
new file mode 100644
index 0000000000..bbc9908991
--- /dev/null
+++ b/src/server/api/private/signin.ts
@@ -0,0 +1,91 @@
+import * as express from 'express';
+import * as bcrypt from 'bcryptjs';
+import * as speakeasy from 'speakeasy';
+import { default as User, ILocalAccount, IUser } from '../models/user';
+import Signin, { pack } from '../models/signin';
+import event from '../event';
+import signin from '../common/signin';
+import config from '../../../conf';
+
+export default async (req: express.Request, res: express.Response) => {
+ res.header('Access-Control-Allow-Origin', config.url);
+ res.header('Access-Control-Allow-Credentials', 'true');
+
+ const username = req.body['username'];
+ const password = req.body['password'];
+ const token = req.body['token'];
+
+ if (typeof username != 'string') {
+ res.sendStatus(400);
+ return;
+ }
+
+ if (typeof password != 'string') {
+ res.sendStatus(400);
+ return;
+ }
+
+ if (token != null && typeof token != 'string') {
+ res.sendStatus(400);
+ return;
+ }
+
+ // Fetch user
+ const user: IUser = await User.findOne({
+ username_lower: username.toLowerCase(),
+ host: null
+ }, {
+ fields: {
+ data: false,
+ 'account.profile': false
+ }
+ });
+
+ if (user === null) {
+ res.status(404).send({
+ error: 'user not found'
+ });
+ return;
+ }
+
+ const account = user.account as ILocalAccount;
+
+ // Compare password
+ const same = await bcrypt.compare(password, account.password);
+
+ if (same) {
+ if (account.two_factor_enabled) {
+ const verified = (speakeasy as any).totp.verify({
+ secret: account.two_factor_secret,
+ encoding: 'base32',
+ token: token
+ });
+
+ if (verified) {
+ signin(res, user, false);
+ } else {
+ res.status(400).send({
+ error: 'invalid token'
+ });
+ }
+ } else {
+ signin(res, user, false);
+ }
+ } else {
+ res.status(400).send({
+ error: 'incorrect password'
+ });
+ }
+
+ // Append signin history
+ const record = await Signin.insert({
+ created_at: new Date(),
+ user_id: user._id,
+ ip: req.ip,
+ headers: req.headers,
+ success: same
+ });
+
+ // Publish signin event
+ event(user._id, 'signin', await pack(record));
+};
diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts
new file mode 100644
index 0000000000..9f55393313
--- /dev/null
+++ b/src/server/api/private/signup.ts
@@ -0,0 +1,165 @@
+import * as uuid from 'uuid';
+import * as express from 'express';
+import * as bcrypt from 'bcryptjs';
+import { generate as generateKeypair } from '../../../crypto_key';
+import recaptcha = require('recaptcha-promise');
+import User, { IUser, validateUsername, validatePassword, pack } from '../models/user';
+import generateUserToken from '../common/generate-native-user-token';
+import config from '../../../conf';
+
+recaptcha.init({
+ secret_key: config.recaptcha.secret_key
+});
+
+const home = {
+ left: [
+ 'profile',
+ 'calendar',
+ 'activity',
+ 'rss',
+ 'trends',
+ 'photo-stream',
+ 'version'
+ ],
+ right: [
+ 'broadcast',
+ 'notifications',
+ 'users',
+ 'polls',
+ 'server',
+ 'donation',
+ 'nav',
+ 'tips'
+ ]
+};
+
+export default async (req: express.Request, res: express.Response) => {
+ // Verify recaptcha
+ // ただしテスト時はこの機構は障害となるため無効にする
+ if (process.env.NODE_ENV !== 'test') {
+ const success = await recaptcha(req.body['g-recaptcha-response']);
+
+ if (!success) {
+ res.status(400).send('recaptcha-failed');
+ return;
+ }
+ }
+
+ const username = req.body['username'];
+ const password = req.body['password'];
+ const name = '名無し';
+
+ // Validate username
+ if (!validateUsername(username)) {
+ res.sendStatus(400);
+ return;
+ }
+
+ // Validate password
+ if (!validatePassword(password)) {
+ res.sendStatus(400);
+ return;
+ }
+
+ // Fetch exist user that same username
+ const usernameExist = await User
+ .count({
+ username_lower: username.toLowerCase(),
+ host: null
+ }, {
+ limit: 1
+ });
+
+ // Check username already used
+ if (usernameExist !== 0) {
+ res.sendStatus(400);
+ return;
+ }
+
+ // Generate hash of password
+ const salt = await bcrypt.genSalt(8);
+ const hash = await bcrypt.hash(password, salt);
+
+ // Generate secret
+ const secret = generateUserToken();
+
+ //#region Construct home data
+ const homeData = [];
+
+ home.left.forEach(widget => {
+ homeData.push({
+ name: widget,
+ id: uuid(),
+ place: 'left',
+ data: {}
+ });
+ });
+
+ home.right.forEach(widget => {
+ homeData.push({
+ name: widget,
+ id: uuid(),
+ place: 'right',
+ data: {}
+ });
+ });
+ //#endregion
+
+ // Create account
+ const account: IUser = await User.insert({
+ avatar_id: null,
+ banner_id: null,
+ created_at: new Date(),
+ description: null,
+ followers_count: 0,
+ following_count: 0,
+ name: name,
+ posts_count: 0,
+ likes_count: 0,
+ liked_count: 0,
+ drive_capacity: 1073741824, // 1GB
+ username: username,
+ username_lower: username.toLowerCase(),
+ host: null,
+ host_lower: null,
+ account: {
+ keypair: generateKeypair(),
+ token: secret,
+ email: null,
+ links: null,
+ password: hash,
+ profile: {
+ bio: null,
+ birthday: null,
+ blood: null,
+ gender: null,
+ handedness: null,
+ height: null,
+ location: null,
+ weight: null
+ },
+ settings: {
+ auto_watch: true
+ },
+ client_settings: {
+ home: homeData
+ }
+ }
+ });
+
+ // Response
+ res.send(await pack(account));
+
+ // Create search index
+ if (config.elasticsearch.enable) {
+ const es = require('../../db/elasticsearch');
+ es.index({
+ index: 'misskey',
+ type: 'user',
+ id: account._id.toString(),
+ body: {
+ username: username
+ }
+ });
+ }
+};