Resolve #6192
This commit is contained in:
@@ -2,12 +2,9 @@ import isNativeToken from './common/is-native-token';
|
||||
import { User } from '../../models/entities/user';
|
||||
import { Users, AccessTokens, Apps } from '../../models';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { AccessToken } from '../../models/entities/access-token';
|
||||
|
||||
type App = {
|
||||
permission: string[];
|
||||
};
|
||||
|
||||
export default async (token: string): Promise<[User | null | undefined, App | null | undefined]> => {
|
||||
export default async (token: string): Promise<[User | null | undefined, AccessToken | null | undefined]> => {
|
||||
if (token == null) {
|
||||
return [null, null];
|
||||
}
|
||||
@@ -45,12 +42,11 @@ export default async (token: string): Promise<[User | null | undefined, App | nu
|
||||
.findOne(accessToken.appId).then(ensure);
|
||||
|
||||
return [user, {
|
||||
id: accessToken.id,
|
||||
permission: app.permission
|
||||
}];
|
||||
} as AccessToken];
|
||||
} else {
|
||||
return [user, {
|
||||
permission: accessToken.permission
|
||||
}];
|
||||
return [user, accessToken];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -4,10 +4,7 @@ import { User } from '../../models/entities/user';
|
||||
import endpoints from './endpoints';
|
||||
import { ApiError } from './error';
|
||||
import { apiLogger } from './logger';
|
||||
|
||||
type App = {
|
||||
permission: string[];
|
||||
};
|
||||
import { AccessToken } from '../../models/entities/access-token';
|
||||
|
||||
const accessDenied = {
|
||||
message: 'Access denied.',
|
||||
@@ -15,8 +12,8 @@ const accessDenied = {
|
||||
id: '56f35758-7dd5-468b-8439-5d6fb8ec9b8e'
|
||||
};
|
||||
|
||||
export default async (endpoint: string, user: User | null | undefined, app: App | null | undefined, data: any, file?: any) => {
|
||||
const isSecure = user != null && app == null;
|
||||
export default async (endpoint: string, user: User | null | undefined, token: AccessToken | null | undefined, data: any, file?: any) => {
|
||||
const isSecure = user != null && token == null;
|
||||
|
||||
const ep = endpoints.find(e => e.name === endpoint);
|
||||
|
||||
@@ -54,7 +51,7 @@ export default async (endpoint: string, user: User | null | undefined, app: App
|
||||
throw new ApiError(accessDenied, { reason: 'You are not a moderator.' });
|
||||
}
|
||||
|
||||
if (app && ep.meta.kind && !app.permission.some(p => p === ep.meta.kind)) {
|
||||
if (token && ep.meta.kind && !token.permission.some(p => p === ep.meta.kind)) {
|
||||
throw new ApiError({
|
||||
message: 'Your app does not have the necessary permissions to use this endpoint.',
|
||||
code: 'PERMISSION_DENIED',
|
||||
@@ -76,7 +73,7 @@ export default async (endpoint: string, user: User | null | undefined, app: App
|
||||
|
||||
// API invoking
|
||||
const before = performance.now();
|
||||
return await ep.exec(data, user, isSecure, file).catch((e: Error) => {
|
||||
return await ep.exec(data, user, token, file).catch((e: Error) => {
|
||||
if (e instanceof ApiError) {
|
||||
throw e;
|
||||
} else {
|
||||
|
@@ -3,6 +3,7 @@ import { ILocalUser } from '../../models/entities/user';
|
||||
import { IEndpointMeta } from './endpoints';
|
||||
import { ApiError } from './error';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { AccessToken } from '../../models/entities/access-token';
|
||||
|
||||
// TODO: defaultが設定されている場合はその型も考慮する
|
||||
type Params<T extends IEndpointMeta> = {
|
||||
@@ -14,12 +15,12 @@ type Params<T extends IEndpointMeta> = {
|
||||
export type Response = Record<string, any> | void;
|
||||
|
||||
type executor<T extends IEndpointMeta> =
|
||||
(params: Params<T>, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, isSecure: boolean, file?: any, cleanup?: Function) =>
|
||||
(params: Params<T>, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any, cleanup?: Function) =>
|
||||
Promise<T['res'] extends undefined ? Response : SchemaType<NonNullable<T['res']>>>;
|
||||
|
||||
export default function <T extends IEndpointMeta>(meta: T, cb: executor<T>)
|
||||
: (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, isSecure: boolean, file?: any) => Promise<any> {
|
||||
return (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, isSecure: boolean, file?: any) => {
|
||||
: (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any) => Promise<any> {
|
||||
return (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any) => {
|
||||
function cleanup() {
|
||||
fs.unlink(file.path, () => {});
|
||||
}
|
||||
@@ -36,7 +37,7 @@ export default function <T extends IEndpointMeta>(meta: T, cb: executor<T>)
|
||||
return Promise.reject(pserr);
|
||||
}
|
||||
|
||||
return cb(ps, user, isSecure, file, cleanup);
|
||||
return cb(ps, user, token, file, cleanup);
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,9 @@ export const meta = {
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps, user, isSecure) => {
|
||||
export default define(meta, async (ps, user, token) => {
|
||||
const isSecure = token == null;
|
||||
|
||||
// Lookup app
|
||||
const ap = await Apps.findOne(ps.appId);
|
||||
|
||||
|
@@ -78,7 +78,7 @@ export const meta = {
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps, user, isSecure, file, cleanup) => {
|
||||
export default define(meta, async (ps, user, _, file, cleanup) => {
|
||||
// Get 'name' parameter
|
||||
let name = ps.name || file.originalname;
|
||||
if (name !== undefined && name !== null) {
|
||||
|
@@ -19,7 +19,9 @@ export const meta = {
|
||||
},
|
||||
};
|
||||
|
||||
export default define(meta, async (ps, user, isSecure) => {
|
||||
export default define(meta, async (ps, user, token) => {
|
||||
const isSecure = token == null;
|
||||
|
||||
return await Users.pack(user, user, {
|
||||
detail: true,
|
||||
includeHasUnreadNotes: true,
|
||||
|
@@ -178,7 +178,9 @@ export const meta = {
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps, user, isSecure) => {
|
||||
export default define(meta, async (ps, user, token) => {
|
||||
const isSecure = token == null;
|
||||
|
||||
const updates = {} as Partial<User>;
|
||||
const profileUpdates = {} as Partial<UserProfile>;
|
||||
|
||||
|
@@ -132,7 +132,8 @@ export default define(meta, async (ps, user) => {
|
||||
});
|
||||
|
||||
// Notify
|
||||
createNotification(note.userId, user.id, 'pollVote', {
|
||||
createNotification(note.userId, 'pollVote', {
|
||||
notifierId: user.id,
|
||||
noteId: note.id,
|
||||
choice: ps.choice
|
||||
});
|
||||
@@ -143,7 +144,8 @@ export default define(meta, async (ps, user) => {
|
||||
userId: Not(user.id),
|
||||
}).then(watchers => {
|
||||
for (const watcher of watchers) {
|
||||
createNotification(watcher.userId, user.id, 'pollVote', {
|
||||
createNotification(watcher.userId, 'pollVote', {
|
||||
notifierId: user.id,
|
||||
noteId: note.id,
|
||||
choice: ps.choice
|
||||
});
|
||||
|
37
src/server/api/endpoints/notifications/create.ts
Normal file
37
src/server/api/endpoints/notifications/create.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import $ from 'cafy';
|
||||
import define from '../../define';
|
||||
import { createNotification } from '../../../../services/create-notification';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notifications'],
|
||||
|
||||
requireCredential: true as const,
|
||||
|
||||
kind: 'write:notifications',
|
||||
|
||||
params: {
|
||||
body: {
|
||||
validator: $.str
|
||||
},
|
||||
|
||||
header: {
|
||||
validator: $.optional.nullable.str
|
||||
},
|
||||
|
||||
icon: {
|
||||
validator: $.optional.nullable.str
|
||||
},
|
||||
},
|
||||
|
||||
errors: {
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps, user, token) => {
|
||||
createNotification(user.id, 'app', {
|
||||
appAccessTokenId: token.id,
|
||||
customBody: ps.body,
|
||||
customHeader: ps.header,
|
||||
customIcon: ps.icon,
|
||||
});
|
||||
});
|
@@ -104,7 +104,8 @@ export default define(meta, async (ps, me) => {
|
||||
} as UserGroupInvitation);
|
||||
|
||||
// 通知を作成
|
||||
createNotification(user.id, me.id, 'groupInvited', {
|
||||
createNotification(user.id, 'groupInvited', {
|
||||
notifierId: me.id,
|
||||
userGroupInvitationId: invitation.id
|
||||
});
|
||||
});
|
||||
|
@@ -9,10 +9,7 @@ import { EventEmitter } from 'events';
|
||||
import { User } from '../../../models/entities/user';
|
||||
import { Users, Followings, Mutings } from '../../../models';
|
||||
import { ApiError } from '../error';
|
||||
|
||||
type App = {
|
||||
permission: string[];
|
||||
};
|
||||
import { AccessToken } from '../../../models/entities/access-token';
|
||||
|
||||
/**
|
||||
* Main stream connection
|
||||
@@ -21,7 +18,7 @@ export default class Connection {
|
||||
public user?: User;
|
||||
public following: User['id'][] = [];
|
||||
public muting: User['id'][] = [];
|
||||
public app: App;
|
||||
public token: AccessToken;
|
||||
private wsConnection: websocket.connection;
|
||||
public subscriber: EventEmitter;
|
||||
private channels: Channel[] = [];
|
||||
@@ -33,12 +30,12 @@ export default class Connection {
|
||||
wsConnection: websocket.connection,
|
||||
subscriber: EventEmitter,
|
||||
user: User | null | undefined,
|
||||
app: App | null | undefined
|
||||
token: AccessToken | null | undefined
|
||||
) {
|
||||
this.wsConnection = wsConnection;
|
||||
this.subscriber = subscriber;
|
||||
if (user) this.user = user;
|
||||
if (app) this.app = app;
|
||||
if (token) this.token = token;
|
||||
|
||||
this.wsConnection.on('message', this.onWsConnectionMessage);
|
||||
|
||||
@@ -86,7 +83,7 @@ export default class Connection {
|
||||
const endpoint = payload.endpoint || payload.ep; // alias
|
||||
|
||||
// 呼び出し
|
||||
call(endpoint, user, this.app, payload.data).then(res => {
|
||||
call(endpoint, user, this.token, payload.data).then(res => {
|
||||
this.sendMessageToWs(`api:${payload.id}`, { res });
|
||||
}).catch((e: ApiError) => {
|
||||
this.sendMessageToWs(`api:${payload.id}`, {
|
||||
|
Reference in New Issue
Block a user