認証の修正 (#7597)
* authenticateのキャッシュを廃止 * 凍結ユーザーがサインイン出来てしまうのを修正 * 凍結ユーザーはストリーミング接続出来ないように * 他人のアクセストークンはrevoke出来ないように, 正常削除を待機するように * ユーザー/アクセストークンを無効化したらストリーミングを切断するように * Revert TODO * ストリーミングterminateは、ユーザー削除後に行うように * signinでsuspendは別のエラーにする * トークン再生成後のストリーミング切断は少し待つように * サスペンド後のストリーミング切断はローカルユーザーのみに
This commit is contained in:
		
							parent
							
								
									62dede02ea
								
							
						
					
					
						commit
						04e27e160e
					
				
					 8 changed files with 41 additions and 15 deletions
				
			
		|  | @ -2,11 +2,6 @@ import isNativeToken from './common/is-native-token'; | |||
| import { User } from '../../models/entities/user'; | ||||
| import { Users, AccessTokens, Apps } from '../../models'; | ||||
| import { AccessToken } from '../../models/entities/access-token'; | ||||
| import { Cache } from '@/misc/cache'; | ||||
| 
 | ||||
| // TODO: TypeORMのカスタムキャッシュプロバイダを使っても良いかも
 | ||||
| // ref. https://github.com/typeorm/typeorm/blob/master/docs/caching.md
 | ||||
| const cache = new Cache<User>(1000 * 60 * 60); | ||||
| 
 | ||||
| export class AuthenticationError extends Error { | ||||
| 	constructor(message: string) { | ||||
|  | @ -21,11 +16,6 @@ export default async (token: string): Promise<[User | null | undefined, App | nu | |||
| 	} | ||||
| 
 | ||||
| 	if (isNativeToken(token)) { | ||||
| 		const cached = cache.get(token); | ||||
| 		if (cached) { | ||||
| 			return [cached, null]; | ||||
| 		} | ||||
| 
 | ||||
| 		// Fetch user
 | ||||
| 		const user = await Users | ||||
| 			.findOne({ token }); | ||||
|  | @ -34,11 +24,8 @@ export default async (token: string): Promise<[User | null | undefined, App | nu | |||
| 			throw new AuthenticationError('user not found'); | ||||
| 		} | ||||
| 
 | ||||
| 		cache.set(token, user); | ||||
| 
 | ||||
| 		return [user, null]; | ||||
| 	} else { | ||||
| 		// TODO: cache
 | ||||
| 		const accessToken = await AccessTokens.findOne({ | ||||
| 			where: [{ | ||||
| 				hash: token.toLowerCase() // app
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ import { Users, Followings, Notifications } from '../../../../models'; | |||
| import { User } from '../../../../models/entities/user'; | ||||
| import { insertModerationLog } from '../../../../services/insert-moderation-log'; | ||||
| import { doPostSuspend } from '../../../../services/suspend-user'; | ||||
| import { publishUserEvent } from '@/services/stream'; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	tags: ['admin'], | ||||
|  | @ -43,6 +44,11 @@ export default define(meta, async (ps, me) => { | |||
| 		targetId: user.id, | ||||
| 	}); | ||||
| 
 | ||||
| 	// Terminate streaming
 | ||||
| 	if (Users.isLocalUser(user)) { | ||||
| 		publishUserEvent(user.id, 'terminate', {}); | ||||
| 	} | ||||
| 
 | ||||
| 	(async () => { | ||||
| 		await doPostSuspend(user).catch(e => {}); | ||||
| 		await unFollowAll(user).catch(e => {}); | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ import * as bcrypt from 'bcryptjs'; | |||
| import define from '../../define'; | ||||
| import { Users, UserProfiles } from '../../../../models'; | ||||
| import { doPostSuspend } from '../../../../services/suspend-user'; | ||||
| import { publishUserEvent } from '@/services/stream'; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	requireCredential: true as const, | ||||
|  | @ -30,4 +31,7 @@ export default define(meta, async (ps, user) => { | |||
| 	await doPostSuspend(user).catch(e => {}); | ||||
| 
 | ||||
| 	await Users.delete(user.id); | ||||
| 
 | ||||
| 	// Terminate streaming
 | ||||
| 	publishUserEvent(user.id, 'terminate', {}); | ||||
| }); | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import $ from 'cafy'; | ||||
| import * as bcrypt from 'bcryptjs'; | ||||
| import { publishMainStream } from '../../../../services/stream'; | ||||
| import { publishMainStream, publishUserEvent } from '../../../../services/stream'; | ||||
| import generateUserToken from '../../common/generate-native-user-token'; | ||||
| import define from '../../define'; | ||||
| import { Users, UserProfiles } from '../../../../models'; | ||||
|  | @ -36,4 +36,9 @@ export default define(meta, async (ps, user) => { | |||
| 
 | ||||
| 	// Publish event
 | ||||
| 	publishMainStream(user.id, 'myTokenRegenerated'); | ||||
| 
 | ||||
| 	// Terminate streaming
 | ||||
| 	setTimeout(() => { | ||||
| 		publishUserEvent(user.id, 'terminate', {}); | ||||
| 	}, 5000); | ||||
| }); | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ import $ from 'cafy'; | |||
| import define from '../../define'; | ||||
| import { AccessTokens } from '../../../../models'; | ||||
| import { ID } from '@/misc/cafy-id'; | ||||
| import { publishUserEvent } from '@/services/stream'; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	requireCredential: true as const, | ||||
|  | @ -19,6 +20,12 @@ export default define(meta, async (ps, user) => { | |||
| 	const token = await AccessTokens.findOne(ps.tokenId); | ||||
| 
 | ||||
| 	if (token) { | ||||
| 		AccessTokens.delete(token.id); | ||||
| 		await AccessTokens.delete({ | ||||
| 			id: ps.tokenId, | ||||
| 			userId: user.id, | ||||
| 		}); | ||||
| 
 | ||||
| 		// Terminate streaming
 | ||||
| 		publishUserEvent(user.id, 'terminate'); | ||||
| 	} | ||||
| }); | ||||
|  |  | |||
|  | @ -46,6 +46,13 @@ export default async (ctx: Koa.Context) => { | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (user.isSuspended) { | ||||
| 		ctx.throw(403, { | ||||
| 			error: 'user is suspended' | ||||
| 		}); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	const profile = await UserProfiles.findOneOrFail(user.id); | ||||
| 
 | ||||
| 	// Compare password
 | ||||
|  |  | |||
|  | @ -92,6 +92,11 @@ export default class Connection { | |||
| 				this.userProfile = body; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'terminate': | ||||
| 				this.wsConnection.close(); | ||||
| 				this.dispose(); | ||||
| 				break; | ||||
| 
 | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
|  |  | |||
|  | @ -22,6 +22,11 @@ module.exports = (server: http.Server) => { | |||
| 		// (現状はエラーがキャッチされておらずサーバーのログに流れて邪魔なので)
 | ||||
| 		const [user, app] = await authenticate(q.i as string); | ||||
| 
 | ||||
| 		if (user?.isSuspended) { | ||||
| 			request.reject(400); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		const connection = request.accept(); | ||||
| 
 | ||||
| 		const ev = new EventEmitter(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue