ストリーム経由でAPIにリクエストできるように
This commit is contained in:
		
							parent
							
								
									91791834be
								
							
						
					
					
						commit
						bd3d57a67f
					
				
					 15 changed files with 137 additions and 179 deletions
				
			
		| 
						 | 
				
			
			@ -444,23 +444,28 @@ export default class MiOS extends EventEmitter {
 | 
			
		|||
		// Append a credential
 | 
			
		||||
		if (this.isSignedIn) (data as any).i = this.i.token;
 | 
			
		||||
 | 
			
		||||
		// TODO
 | 
			
		||||
		//const viaStream = localStorage.getItem('enableExperimental') == 'true';
 | 
			
		||||
		const viaStream = localStorage.getItem('enableExperimental') == 'true';
 | 
			
		||||
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
			/*if (viaStream) {
 | 
			
		||||
			if (viaStream) {
 | 
			
		||||
				const stream = this.stream.borrow();
 | 
			
		||||
				const id = Math.random().toString();
 | 
			
		||||
 | 
			
		||||
				stream.once(`api-res:${id}`, res => {
 | 
			
		||||
					resolve(res);
 | 
			
		||||
					if (res.res) {
 | 
			
		||||
						resolve(res.res);
 | 
			
		||||
					} else {
 | 
			
		||||
						reject(res.e);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				stream.send({
 | 
			
		||||
					type: 'api',
 | 
			
		||||
					id,
 | 
			
		||||
					endpoint,
 | 
			
		||||
					data
 | 
			
		||||
				});
 | 
			
		||||
			} else {*/
 | 
			
		||||
			} else {
 | 
			
		||||
				const req = {
 | 
			
		||||
					id: uuid(),
 | 
			
		||||
					date: new Date(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ export type IApp = {
 | 
			
		|||
	nameId: string;
 | 
			
		||||
	nameIdLower: string;
 | 
			
		||||
	description: string;
 | 
			
		||||
	permission: string;
 | 
			
		||||
	permission: string[];
 | 
			
		||||
	callbackUrl: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,55 +2,33 @@ import * as express from 'express';
 | 
			
		|||
 | 
			
		||||
import { Endpoint } from './endpoints';
 | 
			
		||||
import authenticate from './authenticate';
 | 
			
		||||
import { IAuthContext } from './authenticate';
 | 
			
		||||
import _reply from './reply';
 | 
			
		||||
import limitter from './limitter';
 | 
			
		||||
import call from './call';
 | 
			
		||||
import { IUser } from '../../models/user';
 | 
			
		||||
import { IApp } from '../../models/app';
 | 
			
		||||
 | 
			
		||||
export default async (endpoint: Endpoint, req: express.Request, res: express.Response) => {
 | 
			
		||||
	const reply = _reply.bind(null, res);
 | 
			
		||||
	let ctx: IAuthContext;
 | 
			
		||||
	const reply = (x?: any, y?: any) => {
 | 
			
		||||
		if (x === undefined) {
 | 
			
		||||
			res.sendStatus(204);
 | 
			
		||||
		} else if (typeof x === 'number') {
 | 
			
		||||
			res.status(x).send({
 | 
			
		||||
				error: x === 500 ? 'INTERNAL_ERROR' : y
 | 
			
		||||
			});
 | 
			
		||||
		} else {
 | 
			
		||||
			res.send(x);
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	let user: IUser;
 | 
			
		||||
	let app: IApp;
 | 
			
		||||
 | 
			
		||||
	// Authentication
 | 
			
		||||
	try {
 | 
			
		||||
		ctx = await authenticate(req);
 | 
			
		||||
		[user, app] = await authenticate(req.body['i']);
 | 
			
		||||
	} catch (e) {
 | 
			
		||||
		return reply(403, 'AUTHENTICATION_FAILED');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (endpoint.secure && !ctx.isSecure) {
 | 
			
		||||
		return reply(403, 'ACCESS_DENIED');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (endpoint.withCredential && ctx.user == null) {
 | 
			
		||||
		return reply(401, 'PLZ_SIGNIN');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ctx.app && endpoint.kind) {
 | 
			
		||||
		if (!ctx.app.permission.some(p => p === endpoint.kind)) {
 | 
			
		||||
			return reply(403, 'ACCESS_DENIED');
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (endpoint.withCredential && endpoint.limit) {
 | 
			
		||||
		try {
 | 
			
		||||
			await limitter(endpoint, ctx); // Rate limit
 | 
			
		||||
		} catch (e) {
 | 
			
		||||
			// drop request if limit exceeded
 | 
			
		||||
			return reply(429);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let exec = require(`${__dirname}/endpoints/${endpoint.name}`);
 | 
			
		||||
 | 
			
		||||
	if (endpoint.withFile) {
 | 
			
		||||
		exec = exec.bind(null, req.file);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// API invoking
 | 
			
		||||
	try {
 | 
			
		||||
		const res = await exec(req.body, ctx.user, ctx.app, ctx.isSecure);
 | 
			
		||||
		reply(res);
 | 
			
		||||
	} catch (e) {
 | 
			
		||||
		reply(400, e);
 | 
			
		||||
	}
 | 
			
		||||
	call(endpoint, user, app, req.body, req).then(reply).catch(e => reply(400, e));
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,50 +1,24 @@
 | 
			
		|||
import * as express from 'express';
 | 
			
		||||
import App from '../../models/app';
 | 
			
		||||
import App, { IApp } from '../../models/app';
 | 
			
		||||
import { default as User, IUser } from '../../models/user';
 | 
			
		||||
import AccessToken from '../../models/access-token';
 | 
			
		||||
import isNativeToken from './common/is-native-token';
 | 
			
		||||
 | 
			
		||||
export interface IAuthContext {
 | 
			
		||||
	/**
 | 
			
		||||
	 * App which requested
 | 
			
		||||
	 */
 | 
			
		||||
	app: any;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Authenticated user
 | 
			
		||||
	 */
 | 
			
		||||
	user: IUser;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether requested with a User-Native Token
 | 
			
		||||
	 */
 | 
			
		||||
	isSecure: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default (req: express.Request) => new Promise<IAuthContext>(async (resolve, reject) => {
 | 
			
		||||
	const token = req.body['i'] as string;
 | 
			
		||||
 | 
			
		||||
export default (token: string) => new Promise<[IUser, IApp]>(async (resolve, reject) => {
 | 
			
		||||
	if (token == null) {
 | 
			
		||||
		return resolve({
 | 
			
		||||
			app: null,
 | 
			
		||||
			user: null,
 | 
			
		||||
			isSecure: false
 | 
			
		||||
		});
 | 
			
		||||
		resolve([null, null]);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (isNativeToken(token)) {
 | 
			
		||||
		// Fetch user
 | 
			
		||||
		const user: IUser = await User
 | 
			
		||||
			.findOne({ 'token': token });
 | 
			
		||||
			.findOne({ token });
 | 
			
		||||
 | 
			
		||||
		if (user === null) {
 | 
			
		||||
			return reject('user not found');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return resolve({
 | 
			
		||||
			app: null,
 | 
			
		||||
			user: user,
 | 
			
		||||
			isSecure: true
 | 
			
		||||
		});
 | 
			
		||||
		resolve([user, null]);
 | 
			
		||||
	} else {
 | 
			
		||||
		const accessToken = await AccessToken.findOne({
 | 
			
		||||
			hash: token.toLowerCase()
 | 
			
		||||
| 
						 | 
				
			
			@ -60,10 +34,6 @@ export default (req: express.Request) => new Promise<IAuthContext>(async (resolv
 | 
			
		|||
		const user = await User
 | 
			
		||||
			.findOne({ _id: accessToken.userId });
 | 
			
		||||
 | 
			
		||||
		return resolve({
 | 
			
		||||
			app: app,
 | 
			
		||||
			user: user,
 | 
			
		||||
			isSecure: false
 | 
			
		||||
		});
 | 
			
		||||
		resolve([user, app]);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										55
									
								
								src/server/api/call.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/server/api/call.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
import * as express from 'express';
 | 
			
		||||
 | 
			
		||||
import endpoints, { Endpoint } from './endpoints';
 | 
			
		||||
import limitter from './limitter';
 | 
			
		||||
import { IUser } from '../../models/user';
 | 
			
		||||
import { IApp } from '../../models/app';
 | 
			
		||||
 | 
			
		||||
export default (endpoint: string | Endpoint, user: IUser, app: IApp, data: any, req?: express.Request) => new Promise(async (ok, rej) => {
 | 
			
		||||
	const isSecure = user != null && app == null;
 | 
			
		||||
 | 
			
		||||
	//console.log(endpoint, user, app, data);
 | 
			
		||||
 | 
			
		||||
	const ep = typeof endpoint == 'string' ? endpoints.find(e => e.name == endpoint) : endpoint;
 | 
			
		||||
 | 
			
		||||
	if (ep.secure && !isSecure) {
 | 
			
		||||
		return rej('ACCESS_DENIED');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ep.withCredential && user == null) {
 | 
			
		||||
		return rej('SIGNIN_REQUIRED');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (app && ep.kind) {
 | 
			
		||||
		if (!app.permission.some(p => p === ep.kind)) {
 | 
			
		||||
			return rej('PERMISSION_DENIED');
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ep.withCredential && ep.limit) {
 | 
			
		||||
		try {
 | 
			
		||||
			await limitter(ep, user); // Rate limit
 | 
			
		||||
		} catch (e) {
 | 
			
		||||
			// drop request if limit exceeded
 | 
			
		||||
			return rej('RATE_LIMIT_EXCEEDED');
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let exec = require(`${__dirname}/endpoints/${ep.name}`);
 | 
			
		||||
 | 
			
		||||
	if (ep.withFile && req) {
 | 
			
		||||
		exec = exec.bind(null, req.file);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let res;
 | 
			
		||||
 | 
			
		||||
	// API invoking
 | 
			
		||||
	try {
 | 
			
		||||
		res = await exec(data, user, app);
 | 
			
		||||
	} catch (e) {
 | 
			
		||||
		rej(e);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ok(res);
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -36,14 +36,10 @@ import App, { pack } from '../../../../models/app';
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * Show an app
 | 
			
		||||
 *
 | 
			
		||||
 * @param {any} params
 | 
			
		||||
 * @param {any} user
 | 
			
		||||
 * @param {any} _
 | 
			
		||||
 * @param {any} isSecure
 | 
			
		||||
 * @return {Promise<any>}
 | 
			
		||||
 */
 | 
			
		||||
module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => {
 | 
			
		||||
module.exports = (params, user, app) => new Promise(async (res, rej) => {
 | 
			
		||||
	const isSecure = user != null && app == null;
 | 
			
		||||
 | 
			
		||||
	// Get 'appId' parameter
 | 
			
		||||
	const [appId, appIdErr] = $(params.appId).optional.id().$;
 | 
			
		||||
	if (appIdErr) return rej('invalid appId param');
 | 
			
		||||
| 
						 | 
				
			
			@ -57,16 +53,16 @@ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) =>
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Lookup app
 | 
			
		||||
	const app = appId !== undefined
 | 
			
		||||
	const ap = appId !== undefined
 | 
			
		||||
		? await App.findOne({ _id: appId })
 | 
			
		||||
		: await App.findOne({ nameIdLower: nameId.toLowerCase() });
 | 
			
		||||
 | 
			
		||||
	if (app === null) {
 | 
			
		||||
	if (ap === null) {
 | 
			
		||||
		return rej('app not found');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send response
 | 
			
		||||
	res(await pack(app, user, {
 | 
			
		||||
		includeSecret: isSecure && app.userId.equals(user._id)
 | 
			
		||||
	res(await pack(ap, user, {
 | 
			
		||||
		includeSecret: isSecure && ap.userId.equals(user._id)
 | 
			
		||||
	}));
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,9 @@ import User, { pack } from '../../../models/user';
 | 
			
		|||
/**
 | 
			
		||||
 * Show myself
 | 
			
		||||
 */
 | 
			
		||||
module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => {
 | 
			
		||||
module.exports = (params, user, app) => new Promise(async (res, rej) => {
 | 
			
		||||
	const isSecure = user != null && app == null;
 | 
			
		||||
 | 
			
		||||
	// Serialize
 | 
			
		||||
	res(await pack(user, user, {
 | 
			
		||||
		detail: true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,14 +7,10 @@ import event from '../../../../publishers/stream';
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * Update myself
 | 
			
		||||
 *
 | 
			
		||||
 * @param {any} params
 | 
			
		||||
 * @param {any} user
 | 
			
		||||
 * @param {any} _
 | 
			
		||||
 * @param {boolean} isSecure
 | 
			
		||||
 * @return {Promise<any>}
 | 
			
		||||
 */
 | 
			
		||||
module.exports = async (params, user, _, isSecure) => new Promise(async (res, rej) => {
 | 
			
		||||
module.exports = async (params, user, app) => new Promise(async (res, rej) => {
 | 
			
		||||
	const isSecure = user != null && app == null;
 | 
			
		||||
 | 
			
		||||
	// Get 'name' parameter
 | 
			
		||||
	const [name, nameErr] = $(params.name).optional.nullable.string().pipe(isValidName).$;
 | 
			
		||||
	if (nameErr) return rej('invalid name param');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,9 +35,6 @@ import Meta from '../../../models/meta';
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * Show core info
 | 
			
		||||
 *
 | 
			
		||||
 * @param {any} params
 | 
			
		||||
 * @return {Promise<any>}
 | 
			
		||||
 */
 | 
			
		||||
module.exports = (params) => new Promise(async (res, rej) => {
 | 
			
		||||
	const meta: any = (await Meta.findOne()) || {};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,14 +6,8 @@ import Subscription from '../../../../models/sw-subscription';
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * subscribe service worker
 | 
			
		||||
 *
 | 
			
		||||
 * @param {any} params
 | 
			
		||||
 * @param {any} user
 | 
			
		||||
 * @param {any} _
 | 
			
		||||
 * @param {boolean} isSecure
 | 
			
		||||
 * @return {Promise<any>}
 | 
			
		||||
 */
 | 
			
		||||
module.exports = async (params, user, _, isSecure) => new Promise(async (res, rej) => {
 | 
			
		||||
module.exports = async (params, user, app) => new Promise(async (res, rej) => {
 | 
			
		||||
	// Get 'endpoint' parameter
 | 
			
		||||
	const [endpoint, endpointErr] = $(params.endpoint).string().$;
 | 
			
		||||
	if (endpointErr) return rej('invalid endpoint param');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,6 @@ import * as bodyParser from 'body-parser';
 | 
			
		|||
import * as cors from 'cors';
 | 
			
		||||
import * as multer from 'multer';
 | 
			
		||||
 | 
			
		||||
// import authenticate from './authenticate';
 | 
			
		||||
import endpoints from './endpoints';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,12 +2,12 @@ import * as Limiter from 'ratelimiter';
 | 
			
		|||
import * as debug from 'debug';
 | 
			
		||||
import limiterDB from '../../db/redis';
 | 
			
		||||
import { Endpoint } from './endpoints';
 | 
			
		||||
import { IAuthContext } from './authenticate';
 | 
			
		||||
import getAcct from '../../acct/render';
 | 
			
		||||
import { IUser } from '../../models/user';
 | 
			
		||||
 | 
			
		||||
const log = debug('misskey:limitter');
 | 
			
		||||
 | 
			
		||||
export default (endpoint: Endpoint, ctx: IAuthContext) => new Promise((ok, reject) => {
 | 
			
		||||
export default (endpoint: Endpoint, user: IUser) => new Promise((ok, reject) => {
 | 
			
		||||
	const limitation = endpoint.limit;
 | 
			
		||||
 | 
			
		||||
	const key = limitation.hasOwnProperty('key')
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ export default (endpoint: Endpoint, ctx: IAuthContext) => new Promise((ok, rejec
 | 
			
		|||
	// Short-term limit
 | 
			
		||||
	function min() {
 | 
			
		||||
		const minIntervalLimiter = new Limiter({
 | 
			
		||||
			id: `${ctx.user._id}:${key}:min`,
 | 
			
		||||
			id: `${user._id}:${key}:min`,
 | 
			
		||||
			duration: limitation.minInterval,
 | 
			
		||||
			max: 1,
 | 
			
		||||
			db: limiterDB
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ export default (endpoint: Endpoint, ctx: IAuthContext) => new Promise((ok, rejec
 | 
			
		|||
				return reject('ERR');
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			log(`@${getAcct(ctx.user)} ${endpoint.name} min remaining: ${info.remaining}`);
 | 
			
		||||
			log(`@${getAcct(user)} ${endpoint.name} min remaining: ${info.remaining}`);
 | 
			
		||||
 | 
			
		||||
			if (info.remaining === 0) {
 | 
			
		||||
				reject('BRIEF_REQUEST_INTERVAL');
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +60,7 @@ export default (endpoint: Endpoint, ctx: IAuthContext) => new Promise((ok, rejec
 | 
			
		|||
	// Long term limit
 | 
			
		||||
	function max() {
 | 
			
		||||
		const limiter = new Limiter({
 | 
			
		||||
			id: `${ctx.user._id}:${key}`,
 | 
			
		||||
			id: `${user._id}:${key}`,
 | 
			
		||||
			duration: limitation.duration,
 | 
			
		||||
			max: limitation.max,
 | 
			
		||||
			db: limiterDB
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +71,7 @@ export default (endpoint: Endpoint, ctx: IAuthContext) => new Promise((ok, rejec
 | 
			
		|||
				return reject('ERR');
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			log(`@${getAcct(ctx.user)} ${endpoint.name} max remaining: ${info.remaining}`);
 | 
			
		||||
			log(`@${getAcct(user)} ${endpoint.name} max remaining: ${info.remaining}`);
 | 
			
		||||
 | 
			
		||||
			if (info.remaining === 0) {
 | 
			
		||||
				reject('RATE_LIMIT_EXCEEDED');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +0,0 @@
 | 
			
		|||
import * as express from 'express';
 | 
			
		||||
 | 
			
		||||
export default (res: express.Response, x?: any, y?: any) => {
 | 
			
		||||
	if (x === undefined) {
 | 
			
		||||
		res.sendStatus(204);
 | 
			
		||||
	} else if (typeof x === 'number') {
 | 
			
		||||
		res.status(x).send({
 | 
			
		||||
			error: x === 500 ? 'INTERNAL_ERROR' : y
 | 
			
		||||
		});
 | 
			
		||||
	} else {
 | 
			
		||||
		res.send(x);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -2,14 +2,22 @@ import * as websocket from 'websocket';
 | 
			
		|||
import * as redis from 'redis';
 | 
			
		||||
import * as debug from 'debug';
 | 
			
		||||
 | 
			
		||||
import User from '../../../models/user';
 | 
			
		||||
import User, { IUser } from '../../../models/user';
 | 
			
		||||
import Mute from '../../../models/mute';
 | 
			
		||||
import { pack as packNote } from '../../../models/note';
 | 
			
		||||
import readNotification from '../common/read-notification';
 | 
			
		||||
import call from '../call';
 | 
			
		||||
import { IApp } from '../../../models/app';
 | 
			
		||||
 | 
			
		||||
const log = debug('misskey');
 | 
			
		||||
 | 
			
		||||
export default async function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any) {
 | 
			
		||||
export default async function(
 | 
			
		||||
	request: websocket.request,
 | 
			
		||||
	connection: websocket.connection,
 | 
			
		||||
	subscriber: redis.RedisClient,
 | 
			
		||||
	user: IUser,
 | 
			
		||||
	app: IApp
 | 
			
		||||
) {
 | 
			
		||||
	// Subscribe Home stream channel
 | 
			
		||||
	subscriber.subscribe(`misskey:user-stream:${user._id}`);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +75,17 @@ export default async function(request: websocket.request, connection: websocket.
 | 
			
		|||
 | 
			
		||||
		switch (msg.type) {
 | 
			
		||||
			case 'api':
 | 
			
		||||
				// TODO
 | 
			
		||||
				call(msg.endpoint, user, app, msg.data).then(res => {
 | 
			
		||||
					connection.send(JSON.stringify({
 | 
			
		||||
						type: `api-res:${msg.id}`,
 | 
			
		||||
						body: { res }
 | 
			
		||||
					}));
 | 
			
		||||
				}).catch(e => {
 | 
			
		||||
					connection.send(JSON.stringify({
 | 
			
		||||
						type: `api-res:${msg.id}`,
 | 
			
		||||
						body: { e }
 | 
			
		||||
					}));
 | 
			
		||||
				});
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 'alive':
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,6 @@ import * as http from 'http';
 | 
			
		|||
import * as websocket from 'websocket';
 | 
			
		||||
import * as redis from 'redis';
 | 
			
		||||
import config from '../../config';
 | 
			
		||||
import { default as User, IUser } from '../../models/user';
 | 
			
		||||
import AccessToken from '../../models/access-token';
 | 
			
		||||
import isNativeToken from './common/is-native-token';
 | 
			
		||||
 | 
			
		||||
import homeStream from './stream/home';
 | 
			
		||||
import driveStream from './stream/drive';
 | 
			
		||||
| 
						 | 
				
			
			@ -16,6 +13,7 @@ import serverStream from './stream/server';
 | 
			
		|||
import requestsStream from './stream/requests';
 | 
			
		||||
import channelStream from './stream/channel';
 | 
			
		||||
import { ParsedUrlQuery } from 'querystring';
 | 
			
		||||
import authenticate from './authenticate';
 | 
			
		||||
 | 
			
		||||
module.exports = (server: http.Server) => {
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +51,7 @@ module.exports = (server: http.Server) => {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		const q = request.resourceURL.query as ParsedUrlQuery;
 | 
			
		||||
		const user = await authenticate(q.i as string);
 | 
			
		||||
		const [user, app] = await authenticate(q.i as string);
 | 
			
		||||
 | 
			
		||||
		if (request.resourceURL.pathname === '/othello-game') {
 | 
			
		||||
			othelloGameStream(request, connection, subscriber, user);
 | 
			
		||||
| 
						 | 
				
			
			@ -75,46 +73,9 @@ module.exports = (server: http.Server) => {
 | 
			
		|||
			null;
 | 
			
		||||
 | 
			
		||||
		if (channel !== null) {
 | 
			
		||||
			channel(request, connection, subscriber, user);
 | 
			
		||||
			channel(request, connection, subscriber, user, app);
 | 
			
		||||
		} else {
 | 
			
		||||
			connection.close();
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 接続してきたユーザーを取得します
 | 
			
		||||
 * @param token 送信されてきたトークン
 | 
			
		||||
 */
 | 
			
		||||
function authenticate(token: string): Promise<IUser> {
 | 
			
		||||
	if (token == null) {
 | 
			
		||||
		return Promise.resolve(null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return new Promise(async (resolve, reject) => {
 | 
			
		||||
		if (isNativeToken(token)) {
 | 
			
		||||
			// Fetch user
 | 
			
		||||
			const user: IUser = await User
 | 
			
		||||
				.findOne({
 | 
			
		||||
					host: null,
 | 
			
		||||
					'token': token
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
			resolve(user);
 | 
			
		||||
		} else {
 | 
			
		||||
			const accessToken = await AccessToken.findOne({
 | 
			
		||||
				hash: token
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			if (accessToken == null) {
 | 
			
		||||
				return reject('invalid signature');
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Fetch user
 | 
			
		||||
			const user: IUser = await User
 | 
			
		||||
				.findOne({ _id: accessToken.userId });
 | 
			
		||||
 | 
			
		||||
			resolve(user);
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue