summaryrefslogtreecommitdiff
path: root/src/server/api/private
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2018-03-29 14:51:06 +0900
committerGitHub <noreply@github.com>2018-03-29 14:51:06 +0900
commit0b5597c873d2d9d45be94a18e1b74f44d9925185 (patch)
tree8b4dac3a56cf703650c8207f9279028a8560a96b /src/server/api/private
parentoops (diff)
parentResolve conflicts (diff)
downloadsharkey-0b5597c873d2d9d45be94a18e1b74f44d9925185.tar.gz
sharkey-0b5597c873d2d9d45be94a18e1b74f44d9925185.tar.bz2
sharkey-0b5597c873d2d9d45be94a18e1b74f44d9925185.zip
Merge pull request #1332 from syuilo/pr/1327
Pr/1327
Diffstat (limited to 'src/server/api/private')
-rw-r--r--src/server/api/private/signin.ts91
-rw-r--r--src/server/api/private/signup.ts163
2 files changed, 254 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..4b60f4c752
--- /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({
+ usernameLower: 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.twoFactorEnabled) {
+ const verified = (speakeasy as any).totp.verify({
+ secret: account.twoFactorSecret,
+ 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({
+ createdAt: new Date(),
+ userId: 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..cad9752c45
--- /dev/null
+++ b/src/server/api/private/signup.ts
@@ -0,0 +1,163 @@
+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({
+ usernameLower: 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({
+ avatarId: null,
+ bannerId: null,
+ createdAt: new Date(),
+ description: null,
+ followersCount: 0,
+ followingCount: 0,
+ name: name,
+ postsCount: 0,
+ driveCapacity: 1073741824, // 1GB
+ username: username,
+ usernameLower: username.toLowerCase(),
+ host: null,
+ hostLower: 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: {
+ autoWatch: true
+ },
+ clientSettings: {
+ 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
+ }
+ });
+ }
+};