diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index f86b5e6f96142034e41c0dd1e200bd0d1852cad5..2325bbe093b1d617dfc57c0bceab7bfc23cd528d 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -29,6 +29,7 @@ import { UserNotePining } from '@/models/entities/UserNotePining.js'; import { StatusError } from '@/misc/status-error.js'; import type { UtilityService } from '@/core/UtilityService.js'; import type { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { bindThis } from '@/decorators.js'; import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js'; import { extractApHashtags } from './tag.js'; import type { OnModuleInit } from '@nestjs/common'; @@ -43,37 +44,6 @@ import type { IActor, IObject, IApPropertyValue } from '../type.js'; const nameLength = 128; const summaryLength = 2048; -const services: { - [x: string]: (id: string, username: string) => any -} = { - 'misskey:authentication:twitter': (userId, screenName) => ({ userId, screenName }), - 'misskey:authentication:github': (id, login) => ({ id, login }), - 'misskey:authentication:discord': (id, name) => $discord(id, name), -}; - -const $discord = (id: string, name: string) => { - if (typeof name !== 'string') { - name = 'unknown#0000'; - } - const [username, discriminator] = name.split('#'); - return { id, username, discriminator }; -}; - -function addService(target: { [x: string]: any }, source: IApPropertyValue) { - const service = services[source.name]; - - if (typeof source.value !== 'string') { - source.value = 'unknown'; - } - - const [id, username] = source.value.split('@'); - - if (service) { - target[source.name.split(':')[2]] = service(id, username); - } -} -import { bindThis } from '@/decorators.js'; - @Injectable() export class ApPersonService implements OnModuleInit { private utilityService: UtilityService; @@ -540,22 +510,16 @@ export class ApPersonService implements OnModuleInit { name: string, value: string }[] = []; - const services: { [x: string]: any } = {}; - if (Array.isArray(attachments)) { for (const attachment of attachments.filter(isPropertyValue)) { - if (isPropertyValue(attachment.identifier)) { - addService(services, attachment.identifier); - } else { - fields.push({ - name: attachment.name, - value: this.mfmService.fromHtml(attachment.value), - }); - } + fields.push({ + name: attachment.name, + value: this.mfmService.fromHtml(attachment.value), + }); } } - return { fields, services }; + return { fields }; } @bindThis diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 546e61a26ed0e9304036da19cca81f49d73bdf26..aaa80033b3f36a2bc26f7142b5f6ac903ed254f5 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -489,7 +489,6 @@ export class UserEntityService implements OnModuleInit { hasUnreadMessagingMessage: this.getHasUnreadMessagingMessage(user.id), hasUnreadNotification: this.getHasUnreadNotification(user.id), hasPendingReceivedFollowRequest: this.getHasPendingReceivedFollowRequest(user.id), - integrations: profile!.integrations, mutedWords: profile!.mutedWords, mutedInstances: profile!.mutedInstances, mutingNotificationTypes: profile!.mutingNotificationTypes, diff --git a/packages/backend/src/models/entities/Meta.ts b/packages/backend/src/models/entities/Meta.ts index 5d222a6da1952f5941d383f3bc01c076d1db28f6..9d777c623640d259987300e9e79cd8feaec7d78c 100644 --- a/packages/backend/src/models/entities/Meta.ts +++ b/packages/backend/src/models/entities/Meta.ts @@ -279,57 +279,6 @@ export class Meta { }) public swPrivateKey: string | null; - @Column('boolean', { - default: false, - }) - public enableTwitterIntegration: boolean; - - @Column('varchar', { - length: 128, - nullable: true, - }) - public twitterConsumerKey: string | null; - - @Column('varchar', { - length: 128, - nullable: true, - }) - public twitterConsumerSecret: string | null; - - @Column('boolean', { - default: false, - }) - public enableGithubIntegration: boolean; - - @Column('varchar', { - length: 128, - nullable: true, - }) - public githubClientId: string | null; - - @Column('varchar', { - length: 128, - nullable: true, - }) - public githubClientSecret: string | null; - - @Column('boolean', { - default: false, - }) - public enableDiscordIntegration: boolean; - - @Column('varchar', { - length: 128, - nullable: true, - }) - public discordClientId: string | null; - - @Column('varchar', { - length: 128, - nullable: true, - }) - public discordClientSecret: string | null; - @Column('varchar', { length: 128, nullable: true, diff --git a/packages/backend/src/models/entities/UserProfile.ts b/packages/backend/src/models/entities/UserProfile.ts index 86df8d5d98e774f1cb27d00e34e9c5fb7313ad49..1ff261cda31cb649e56f3def47dc066065a4bed0 100644 --- a/packages/backend/src/models/entities/UserProfile.ts +++ b/packages/backend/src/models/entities/UserProfile.ts @@ -184,11 +184,6 @@ export class UserProfile { @JoinColumn() public pinnedPage: Page | null; - @Column('jsonb', { - default: {}, - }) - public integrations: Record<string, any>; - @Index() @Column('boolean', { default: false, select: false, diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts index aac5e9332c7aa4edbdd7656bb774e8dbdc706d55..1fc93525399f2f2dd1f5f1469217ec26a2173b2b 100644 --- a/packages/backend/src/models/schema/user.ts +++ b/packages/backend/src/models/schema/user.ts @@ -323,10 +323,6 @@ export const packedMeDetailedOnlySchema = { type: 'boolean', nullable: false, optional: false, }, - integrations: { - type: 'object', - nullable: true, optional: false, - }, mutedWords: { type: 'array', nullable: false, optional: false, diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts index 024ddfe632b4574f6cc08c45077df1e6c8298479..a43630c0411f0c5f1ca50f51e4008f2cf8a3b413 100644 --- a/packages/backend/src/server/NodeinfoServerService.ts +++ b/packages/backend/src/server/NodeinfoServerService.ts @@ -111,9 +111,6 @@ export class NodeinfoServerService { enableHcaptcha: meta.enableHcaptcha, enableRecaptcha: meta.enableRecaptcha, maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, - enableTwitterIntegration: meta.enableTwitterIntegration, - enableGithubIntegration: meta.enableGithubIntegration, - enableDiscordIntegration: meta.enableDiscordIntegration, enableEmail: meta.enableEmail, enableServiceWorker: meta.enableServiceWorker, proxyAccountName: proxyAccount ? proxyAccount.username : null, diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts index 9dc1527698091e5963ecad41b75ce6a1ef682030..b605f3c8abb32d1e438b329c677097b509ca9849 100644 --- a/packages/backend/src/server/ServerModule.ts +++ b/packages/backend/src/server/ServerModule.ts @@ -7,9 +7,6 @@ import { NodeinfoServerService } from './NodeinfoServerService.js'; import { ServerService } from './ServerService.js'; import { WellKnownServerService } from './WellKnownServerService.js'; import { GetterService } from './api/GetterService.js'; -import { DiscordServerService } from './api/integration/DiscordServerService.js'; -import { GithubServerService } from './api/integration/GithubServerService.js'; -import { TwitterServerService } from './api/integration/TwitterServerService.js'; import { ChannelsService } from './api/stream/ChannelsService.js'; import { ActivityPubServerService } from './ActivityPubServerService.js'; import { ApiLoggerService } from './api/ApiLoggerService.js'; @@ -54,9 +51,6 @@ import { UserListChannelService } from './api/stream/channels/user-list.js'; ServerService, WellKnownServerService, GetterService, - DiscordServerService, - GithubServerService, - TwitterServerService, ChannelsService, ApiCallService, ApiLoggerService, diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts index b29c9616cc8d1fbc1975921ec2fa145343f0cab4..e406949cd400d2782172465d8092bf87cbe4fed8 100644 --- a/packages/backend/src/server/api/ApiServerService.ts +++ b/packages/backend/src/server/api/ApiServerService.ts @@ -12,9 +12,6 @@ import endpoints, { IEndpoint } from './endpoints.js'; import { ApiCallService } from './ApiCallService.js'; import { SignupApiService } from './SignupApiService.js'; import { SigninApiService } from './SigninApiService.js'; -import { GithubServerService } from './integration/GithubServerService.js'; -import { DiscordServerService } from './integration/DiscordServerService.js'; -import { TwitterServerService } from './integration/TwitterServerService.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; @Injectable() @@ -38,9 +35,6 @@ export class ApiServerService { private apiCallService: ApiCallService, private signupApiService: SignupApiService, private signinApiService: SigninApiService, - private githubServerService: GithubServerService, - private discordServerService: DiscordServerService, - private twitterServerService: TwitterServerService, ) { //this.createServer = this.createServer.bind(this); } @@ -133,10 +127,6 @@ export class ApiServerService { fastify.post<{ Body: { code: string; } }>('/signup-pending', (request, reply) => this.signupApiService.signupPending(request, reply)); - fastify.register(this.discordServerService.create); - fastify.register(this.githubServerService.create); - fastify.register(this.twitterServerService.create); - fastify.get('/v1/instance/peers', async (request, reply) => { const instances = await this.instancesRepository.find({ select: ['host'], diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index b3938270540437e8481e796e434207fb327d5f0c..2b19104ea7b2b83ec27298a90f836df3b9eae875 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -138,18 +138,6 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, - enableTwitterIntegration: { - type: 'boolean', - optional: false, nullable: false, - }, - enableGithubIntegration: { - type: 'boolean', - optional: false, nullable: false, - }, - enableDiscordIntegration: { - type: 'boolean', - optional: false, nullable: false, - }, enableServiceWorker: { type: 'boolean', optional: false, nullable: false, @@ -223,30 +211,6 @@ export const meta = { optional: true, nullable: true, format: 'id', }, - twitterConsumerKey: { - type: 'string', - optional: true, nullable: true, - }, - twitterConsumerSecret: { - type: 'string', - optional: true, nullable: true, - }, - githubClientId: { - type: 'string', - optional: true, nullable: true, - }, - githubClientSecret: { - type: 'string', - optional: true, nullable: true, - }, - discordClientId: { - type: 'string', - optional: true, nullable: true, - }, - discordClientSecret: { - type: 'string', - optional: true, nullable: true, - }, summaryProxy: { type: 'string', optional: true, nullable: true, @@ -389,9 +353,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { defaultLightTheme: instance.defaultLightTheme, defaultDarkTheme: instance.defaultDarkTheme, enableEmail: instance.enableEmail, - enableTwitterIntegration: instance.enableTwitterIntegration, - enableGithubIntegration: instance.enableGithubIntegration, - enableDiscordIntegration: instance.enableDiscordIntegration, enableServiceWorker: instance.enableServiceWorker, translatorAvailable: instance.deeplAuthKey != null, pinnedPages: instance.pinnedPages, @@ -409,12 +370,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically, enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos, proxyAccountId: instance.proxyAccountId, - twitterConsumerKey: instance.twitterConsumerKey, - twitterConsumerSecret: instance.twitterConsumerSecret, - githubClientId: instance.githubClientId, - githubClientSecret: instance.githubClientSecret, - discordClientId: instance.discordClientId, - discordClientSecret: instance.discordClientSecret, summalyProxy: instance.summalyProxy, email: instance.email, smtpSecure: instance.smtpSecure, diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 94603cc91aef70a887706d965c2ff59a27a72bab..823af6d8bec1662489d13067ed278113cb429932 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -65,11 +65,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { }; } - const maskedKeys = ['accessToken', 'accessTokenSecret', 'refreshToken']; - Object.keys(profile.integrations).forEach(integration => { - maskedKeys.forEach(key => profile.integrations[integration][key] = '<MASKED>'); - }); - const signins = await this.signinsRepository.findBy({ userId: user.id }); const roles = await this.roleService.getUserRoles(user.id); @@ -84,7 +79,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { carefulBot: profile.carefulBot, injectFeaturedNote: profile.injectFeaturedNote, receiveAnnouncementEmail: profile.receiveAnnouncementEmail, - integrations: profile.integrations, mutedWords: profile.mutedWords, mutedInstances: profile.mutedInstances, mutingNotificationTypes: profile.mutingNotificationTypes, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index aacd634ed84326474078ae42b88186d79e24dfad..354ef22aa78cfb44b923bb60fda20a0d103e9d83 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -68,15 +68,6 @@ export const paramDef = { summalyProxy: { type: 'string', nullable: true }, deeplAuthKey: { type: 'string', nullable: true }, deeplIsPro: { type: 'boolean' }, - enableTwitterIntegration: { type: 'boolean' }, - twitterConsumerKey: { type: 'string', nullable: true }, - twitterConsumerSecret: { type: 'string', nullable: true }, - enableGithubIntegration: { type: 'boolean' }, - githubClientId: { type: 'string', nullable: true }, - githubClientSecret: { type: 'string', nullable: true }, - enableDiscordIntegration: { type: 'boolean' }, - discordClientId: { type: 'string', nullable: true }, - discordClientSecret: { type: 'string', nullable: true }, enableEmail: { type: 'boolean' }, email: { type: 'string', nullable: true }, smtpSecure: { type: 'boolean' }, @@ -270,42 +261,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { set.summalyProxy = ps.summalyProxy; } - if (ps.enableTwitterIntegration !== undefined) { - set.enableTwitterIntegration = ps.enableTwitterIntegration; - } - - if (ps.twitterConsumerKey !== undefined) { - set.twitterConsumerKey = ps.twitterConsumerKey; - } - - if (ps.twitterConsumerSecret !== undefined) { - set.twitterConsumerSecret = ps.twitterConsumerSecret; - } - - if (ps.enableGithubIntegration !== undefined) { - set.enableGithubIntegration = ps.enableGithubIntegration; - } - - if (ps.githubClientId !== undefined) { - set.githubClientId = ps.githubClientId; - } - - if (ps.githubClientSecret !== undefined) { - set.githubClientSecret = ps.githubClientSecret; - } - - if (ps.enableDiscordIntegration !== undefined) { - set.enableDiscordIntegration = ps.enableDiscordIntegration; - } - - if (ps.discordClientId !== undefined) { - set.discordClientId = ps.discordClientId; - } - - if (ps.discordClientSecret !== undefined) { - set.discordClientSecret = ps.discordClientSecret; - } - if (ps.enableEmail !== undefined) { set.enableEmail = ps.enableEmail; } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 89fa5031738f5a4fba766c4f9d7fde228a27d9bf..3baf9453237e70708ee992dc4e819453fc6cb164 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -169,18 +169,6 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, - enableTwitterIntegration: { - type: 'boolean', - optional: false, nullable: false, - }, - enableGithubIntegration: { - type: 'boolean', - optional: false, nullable: false, - }, - enableDiscordIntegration: { - type: 'boolean', - optional: false, nullable: false, - }, enableServiceWorker: { type: 'boolean', optional: false, nullable: false, @@ -225,18 +213,6 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, - twitter: { - type: 'boolean', - optional: false, nullable: false, - }, - github: { - type: 'boolean', - optional: false, nullable: false, - }, - discord: { - type: 'boolean', - optional: false, nullable: false, - }, serviceWorker: { type: 'boolean', optional: false, nullable: false, @@ -325,11 +301,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { imageUrl: ad.imageUrl, })), enableEmail: instance.enableEmail, - - enableTwitterIntegration: instance.enableTwitterIntegration, - enableGithubIntegration: instance.enableGithubIntegration, - enableDiscordIntegration: instance.enableDiscordIntegration, - enableServiceWorker: instance.enableServiceWorker, translatorAvailable: instance.deeplAuthKey != null, @@ -358,9 +329,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { recaptcha: instance.enableRecaptcha, turnstile: instance.enableTurnstile, objectStorage: instance.useObjectStorage, - twitter: instance.enableTwitterIntegration, - github: instance.enableGithubIntegration, - discord: instance.enableDiscordIntegration, serviceWorker: instance.enableServiceWorker, miauth: true, }; diff --git a/packages/backend/src/server/api/integration/DiscordServerService.ts b/packages/backend/src/server/api/integration/DiscordServerService.ts deleted file mode 100644 index cbced901e47cf5007b5a9036401a962fd0e8885a..0000000000000000000000000000000000000000 --- a/packages/backend/src/server/api/integration/DiscordServerService.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import Redis from 'ioredis'; -import { OAuth2 } from 'oauth'; -import { v4 as uuid } from 'uuid'; -import { IsNull } from 'typeorm'; -import type { Config } from '@/config.js'; -import type { UserProfilesRepository, UsersRepository } from '@/models/index.js'; -import { DI } from '@/di-symbols.js'; -import { HttpRequestService } from '@/core/HttpRequestService.js'; -import type { ILocalUser } from '@/models/entities/User.js'; -import { GlobalEventService } from '@/core/GlobalEventService.js'; -import { MetaService } from '@/core/MetaService.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { FastifyReplyError } from '@/misc/fastify-reply-error.js'; -import { bindThis } from '@/decorators.js'; -import { SigninService } from '../SigninService.js'; -import type { FastifyInstance, FastifyRequest, FastifyPluginOptions } from 'fastify'; - -@Injectable() -export class DiscordServerService { - constructor( - @Inject(DI.config) - private config: Config, - - @Inject(DI.redis) - private redisClient: Redis.Redis, - - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.userProfilesRepository) - private userProfilesRepository: UserProfilesRepository, - - private userEntityService: UserEntityService, - private httpRequestService: HttpRequestService, - private globalEventService: GlobalEventService, - private metaService: MetaService, - private signinService: SigninService, - ) { - //this.create = this.create.bind(this); - } - - @bindThis - public create(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { - fastify.get('/disconnect/discord', async (request, reply) => { - if (!this.compareOrigin(request)) { - throw new FastifyReplyError(400, 'invalid origin'); - } - - const userToken = this.getUserToken(request); - if (!userToken) { - throw new FastifyReplyError(400, 'signin required'); - } - - const user = await this.usersRepository.findOneByOrFail({ - host: IsNull(), - token: userToken, - }); - - const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - - delete profile.integrations.discord; - - await this.userProfilesRepository.update(user.id, { - integrations: profile.integrations, - }); - - // Publish i updated event - this.globalEventService.publishMainStream(user.id, 'meUpdated', await this.userEntityService.pack(user, user, { - detail: true, - includeSecrets: true, - })); - - return 'Discordã®é€£æºã‚’解除ã—ã¾ã—㟠:v:'; - }); - - const getOAuth2 = async () => { - const meta = await this.metaService.fetch(true); - - if (meta.enableDiscordIntegration) { - return new OAuth2( - meta.discordClientId!, - meta.discordClientSecret!, - 'https://discord.com/', - 'api/oauth2/authorize', - 'api/oauth2/token'); - } else { - return null; - } - }; - - fastify.get('/connect/discord', async (request, reply) => { - if (!this.compareOrigin(request)) { - throw new FastifyReplyError(400, 'invalid origin'); - } - - const userToken = this.getUserToken(request); - if (!userToken) { - throw new FastifyReplyError(400, 'signin required'); - } - - const params = { - redirect_uri: `${this.config.url}/api/dc/cb`, - scope: ['identify'], - state: uuid(), - response_type: 'code', - }; - - this.redisClient.set(userToken, JSON.stringify(params)); - - const oauth2 = await getOAuth2(); - reply.redirect(oauth2!.getAuthorizeUrl(params)); - }); - - fastify.get('/signin/discord', async (request, reply) => { - const sessid = uuid(); - - const params = { - redirect_uri: `${this.config.url}/api/dc/cb`, - scope: ['identify'], - state: uuid(), - response_type: 'code', - }; - - reply.setCookie('signin_with_discord_sid', sessid, { - path: '/', - secure: this.config.url.startsWith('https'), - httpOnly: true, - }); - - this.redisClient.set(sessid, JSON.stringify(params)); - - const oauth2 = await getOAuth2(); - reply.redirect(oauth2!.getAuthorizeUrl(params)); - }); - - fastify.get<{ Querystring: { code: string; state: string; } }>('/dc/cb', async (request, reply) => { - const userToken = this.getUserToken(request); - - const oauth2 = await getOAuth2(); - - if (!userToken) { - const sessid = request.cookies['signin_with_discord_sid']; - - if (!sessid) { - throw new FastifyReplyError(400, 'invalid session'); - } - - const code = request.query.code; - - if (!code || typeof code !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const { redirect_uri, state } = await new Promise<any>((res, rej) => { - this.redisClient.get(sessid, async (_, state) => { - if (state == null) throw new Error('empty state'); - res(JSON.parse(state)); - }); - }); - - if (request.query.state !== state) { - throw new FastifyReplyError(400, 'invalid session'); - } - - const { accessToken, refreshToken, expiresDate } = await new Promise<any>((res, rej) => - oauth2!.getOAuthAccessToken(code, { - grant_type: 'authorization_code', - redirect_uri, - }, (err, accessToken, refreshToken, result) => { - if (err) { - rej(err); - } else if (result.error) { - rej(result.error); - } else { - res({ - accessToken, - refreshToken, - expiresDate: Date.now() + Number(result.expires_in) * 1000, - }); - } - })); - - const { id, username, discriminator } = (await this.httpRequestService.getJson('https://discord.com/api/users/@me', '*/*', { - 'Authorization': `Bearer ${accessToken}`, - })) as Record<string, unknown>; - - if (typeof id !== 'string' || typeof username !== 'string' || typeof discriminator !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const profile = await this.userProfilesRepository.createQueryBuilder() - .where('"integrations"->\'discord\'->>\'id\' = :id', { id: id }) - .andWhere('"userHost" IS NULL') - .getOne(); - - if (profile == null) { - throw new FastifyReplyError(404, `@${username}#${discriminator}ã¨é€£æºã—ã¦ã„ã‚‹Misskeyアカウントã¯ã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸ...`); - } - - await this.userProfilesRepository.update(profile.userId, { - integrations: { - ...profile.integrations, - discord: { - id: id, - accessToken: accessToken, - refreshToken: refreshToken, - expiresDate: expiresDate, - username: username, - discriminator: discriminator, - }, - }, - }); - - return this.signinService.signin(request, reply, await this.usersRepository.findOneBy({ id: profile.userId }) as ILocalUser, true); - } else { - const code = request.query.code; - - if (!code || typeof code !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const { redirect_uri, state } = await new Promise<any>((res, rej) => { - this.redisClient.get(userToken, async (_, state) => { - if (state == null) throw new Error('empty state'); - res(JSON.parse(state)); - }); - }); - - if (request.query.state !== state) { - throw new FastifyReplyError(400, 'invalid session'); - } - - const { accessToken, refreshToken, expiresDate } = await new Promise<any>((res, rej) => - oauth2!.getOAuthAccessToken(code, { - grant_type: 'authorization_code', - redirect_uri, - }, (err, accessToken, refreshToken, result) => { - if (err) { - rej(err); - } else if (result.error) { - rej(result.error); - } else { - res({ - accessToken, - refreshToken, - expiresDate: Date.now() + Number(result.expires_in) * 1000, - }); - } - })); - - const { id, username, discriminator } = (await this.httpRequestService.getJson('https://discord.com/api/users/@me', '*/*', { - 'Authorization': `Bearer ${accessToken}`, - })) as Record<string, unknown>; - if (typeof id !== 'string' || typeof username !== 'string' || typeof discriminator !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const user = await this.usersRepository.findOneByOrFail({ - host: IsNull(), - token: userToken, - }); - - const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - - await this.userProfilesRepository.update(user.id, { - integrations: { - ...profile.integrations, - discord: { - accessToken: accessToken, - refreshToken: refreshToken, - expiresDate: expiresDate, - id: id, - username: username, - discriminator: discriminator, - }, - }, - }); - - // Publish i updated event - this.globalEventService.publishMainStream(user.id, 'meUpdated', await this.userEntityService.pack(user, user, { - detail: true, - includeSecrets: true, - })); - - return `Discord: @${username}#${discriminator} ã‚’ã€Misskey: @${user.username} ã«æŽ¥ç¶šã—ã¾ã—ãŸï¼`; - } - }); - - done(); - } - - @bindThis - private getUserToken(request: FastifyRequest): string | null { - return ((request.headers['cookie'] ?? '').match(/igi=(\w+)/) ?? [null, null])[1]; - } - - @bindThis - private compareOrigin(request: FastifyRequest): boolean { - function normalizeUrl(url?: string): string { - return url ? url.endsWith('/') ? url.substr(0, url.length - 1) : url : ''; - } - - const referer = request.headers['referer']; - - return (normalizeUrl(referer) === normalizeUrl(this.config.url)); - } -} diff --git a/packages/backend/src/server/api/integration/GithubServerService.ts b/packages/backend/src/server/api/integration/GithubServerService.ts deleted file mode 100644 index 76089c93596922f517260e1738e3a392661157c9..0000000000000000000000000000000000000000 --- a/packages/backend/src/server/api/integration/GithubServerService.ts +++ /dev/null @@ -1,280 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import Redis from 'ioredis'; -import { OAuth2 } from 'oauth'; -import { v4 as uuid } from 'uuid'; -import { IsNull } from 'typeorm'; -import type { Config } from '@/config.js'; -import type { UserProfilesRepository, UsersRepository } from '@/models/index.js'; -import { DI } from '@/di-symbols.js'; -import { HttpRequestService } from '@/core/HttpRequestService.js'; -import type { ILocalUser } from '@/models/entities/User.js'; -import { GlobalEventService } from '@/core/GlobalEventService.js'; -import { MetaService } from '@/core/MetaService.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { FastifyReplyError } from '@/misc/fastify-reply-error.js'; -import { bindThis } from '@/decorators.js'; -import { SigninService } from '../SigninService.js'; -import type { FastifyInstance, FastifyRequest, FastifyPluginOptions } from 'fastify'; - -@Injectable() -export class GithubServerService { - constructor( - @Inject(DI.config) - private config: Config, - - @Inject(DI.redis) - private redisClient: Redis.Redis, - - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.userProfilesRepository) - private userProfilesRepository: UserProfilesRepository, - - private userEntityService: UserEntityService, - private httpRequestService: HttpRequestService, - private globalEventService: GlobalEventService, - private metaService: MetaService, - private signinService: SigninService, - ) { - //this.create = this.create.bind(this); - } - - @bindThis - public create(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { - fastify.get('/disconnect/github', async (request, reply) => { - if (!this.compareOrigin(request)) { - throw new FastifyReplyError(400, 'invalid origin'); - } - - const userToken = this.getUserToken(request); - if (!userToken) { - throw new FastifyReplyError(400, 'signin required'); - } - - const user = await this.usersRepository.findOneByOrFail({ - host: IsNull(), - token: userToken, - }); - - const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - - delete profile.integrations.github; - - await this.userProfilesRepository.update(user.id, { - integrations: profile.integrations, - }); - - // Publish i updated event - this.globalEventService.publishMainStream(user.id, 'meUpdated', await this.userEntityService.pack(user, user, { - detail: true, - includeSecrets: true, - })); - - return 'GitHubã®é€£æºã‚’解除ã—ã¾ã—㟠:v:'; - }); - - const getOath2 = async () => { - const meta = await this.metaService.fetch(true); - - if (meta.enableGithubIntegration && meta.githubClientId && meta.githubClientSecret) { - return new OAuth2( - meta.githubClientId, - meta.githubClientSecret, - 'https://github.com/', - 'login/oauth/authorize', - 'login/oauth/access_token'); - } else { - return null; - } - }; - - fastify.get('/connect/github', async (request, reply) => { - if (!this.compareOrigin(request)) { - throw new FastifyReplyError(400, 'invalid origin'); - } - - const userToken = this.getUserToken(request); - if (!userToken) { - throw new FastifyReplyError(400, 'signin required'); - } - - const params = { - redirect_uri: `${this.config.url}/api/gh/cb`, - scope: ['read:user'], - state: uuid(), - }; - - this.redisClient.set(userToken, JSON.stringify(params)); - - const oauth2 = await getOath2(); - reply.redirect(oauth2!.getAuthorizeUrl(params)); - }); - - fastify.get('/signin/github', async (request, reply) => { - const sessid = uuid(); - - const params = { - redirect_uri: `${this.config.url}/api/gh/cb`, - scope: ['read:user'], - state: uuid(), - }; - - reply.setCookie('signin_with_github_sid', sessid, { - path: '/', - secure: this.config.url.startsWith('https'), - httpOnly: true, - }); - - this.redisClient.set(sessid, JSON.stringify(params)); - - const oauth2 = await getOath2(); - reply.redirect(oauth2!.getAuthorizeUrl(params)); - }); - - fastify.get<{ Querystring: { code: string; state: string; } }>('/gh/cb', async (request, reply) => { - const userToken = this.getUserToken(request); - - const oauth2 = await getOath2(); - - if (!userToken) { - const sessid = request.cookies['signin_with_github_sid']; - - if (!sessid) { - throw new FastifyReplyError(400, 'invalid session'); - } - - const code = request.query.code; - - if (!code || typeof code !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const { redirect_uri, state } = await new Promise<any>((res, rej) => { - this.redisClient.get(sessid, async (_, state) => { - if (state == null) throw new Error('empty state'); - res(JSON.parse(state)); - }); - }); - - if (request.query.state !== state) { - throw new FastifyReplyError(400, 'invalid session'); - } - - const { accessToken } = await new Promise<{ accessToken: string }>((res, rej) => - oauth2!.getOAuthAccessToken(code, { - redirect_uri, - }, (err, accessToken, refresh, result) => { - if (err) { - rej(err); - } else if (result.error) { - rej(result.error); - } else { - res({ accessToken }); - } - })); - - const { login, id } = (await this.httpRequestService.getJson('https://api.github.com/user', 'application/vnd.github.v3+json', { - 'Authorization': `bearer ${accessToken}`, - })) as Record<string, unknown>; - if (typeof login !== 'string' || typeof id !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const link = await this.userProfilesRepository.createQueryBuilder() - .where('"integrations"->\'github\'->>\'id\' = :id', { id: id }) - .andWhere('"userHost" IS NULL') - .getOne(); - - if (link == null) { - throw new FastifyReplyError(404, `@${login}ã¨é€£æºã—ã¦ã„ã‚‹Misskeyアカウントã¯ã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸ...`); - } - - return this.signinService.signin(request, reply, await this.usersRepository.findOneBy({ id: link.userId }) as ILocalUser, true); - } else { - const code = request.query.code; - - if (!code || typeof code !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const { redirect_uri, state } = await new Promise<any>((res, rej) => { - this.redisClient.get(userToken, async (_, state) => { - if (state == null) throw new Error('empty state'); - res(JSON.parse(state)); - }); - }); - - if (request.query.state !== state) { - throw new FastifyReplyError(400, 'invalid session'); - } - - const { accessToken } = await new Promise<{ accessToken: string }>((res, rej) => - oauth2!.getOAuthAccessToken( - code, - { redirect_uri }, - (err, accessToken, refresh, result) => { - if (err) { - rej(err); - } else if (result.error) { - rej(result.error); - } else { - res({ accessToken }); - } - })); - - const { login, id } = (await this.httpRequestService.getJson('https://api.github.com/user', 'application/vnd.github.v3+json', { - 'Authorization': `bearer ${accessToken}`, - })) as Record<string, unknown>; - - if (typeof login !== 'string' || typeof id !== 'number') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const user = await this.usersRepository.findOneByOrFail({ - host: IsNull(), - token: userToken, - }); - - const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - - await this.userProfilesRepository.update(user.id, { - integrations: { - ...profile.integrations, - github: { - accessToken: accessToken, - id: id, - login: login, - }, - }, - }); - - // Publish i updated event - this.globalEventService.publishMainStream(user.id, 'meUpdated', await this.userEntityService.pack(user, user, { - detail: true, - includeSecrets: true, - })); - - return `GitHub: @${login} ã‚’ã€Misskey: @${user.username} ã«æŽ¥ç¶šã—ã¾ã—ãŸï¼`; - } - }); - - done(); - } - - @bindThis - private getUserToken(request: FastifyRequest): string | null { - return ((request.headers['cookie'] ?? '').match(/igi=(\w+)/) ?? [null, null])[1]; - } - - @bindThis - private compareOrigin(request: FastifyRequest): boolean { - function normalizeUrl(url?: string): string { - return url ? url.endsWith('/') ? url.substr(0, url.length - 1) : url : ''; - } - - const referer = request.headers['referer']; - - return (normalizeUrl(referer) === normalizeUrl(this.config.url)); - } -} diff --git a/packages/backend/src/server/api/integration/TwitterServerService.ts b/packages/backend/src/server/api/integration/TwitterServerService.ts deleted file mode 100644 index f31a788d314879b22dfd6b25c477413b447d3cb9..0000000000000000000000000000000000000000 --- a/packages/backend/src/server/api/integration/TwitterServerService.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import Redis from 'ioredis'; -import { v4 as uuid } from 'uuid'; -import { IsNull } from 'typeorm'; -import * as autwh from 'autwh'; -import type { Config } from '@/config.js'; -import type { UserProfilesRepository, UsersRepository } from '@/models/index.js'; -import { DI } from '@/di-symbols.js'; -import { HttpRequestService } from '@/core/HttpRequestService.js'; -import type { ILocalUser } from '@/models/entities/User.js'; -import { GlobalEventService } from '@/core/GlobalEventService.js'; -import { MetaService } from '@/core/MetaService.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { FastifyReplyError } from '@/misc/fastify-reply-error.js'; -import { bindThis } from '@/decorators.js'; -import { SigninService } from '../SigninService.js'; -import type { FastifyInstance, FastifyRequest, FastifyPluginOptions } from 'fastify'; - -@Injectable() -export class TwitterServerService { - constructor( - @Inject(DI.config) - private config: Config, - - @Inject(DI.redis) - private redisClient: Redis.Redis, - - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.userProfilesRepository) - private userProfilesRepository: UserProfilesRepository, - - private userEntityService: UserEntityService, - private httpRequestService: HttpRequestService, - private globalEventService: GlobalEventService, - private metaService: MetaService, - private signinService: SigninService, - ) { - //this.create = this.create.bind(this); - } - - @bindThis - public create(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { - fastify.get('/disconnect/twitter', async (request, reply) => { - if (!this.compareOrigin(request)) { - throw new FastifyReplyError(400, 'invalid origin'); - } - - const userToken = this.getUserToken(request); - if (userToken == null) { - throw new FastifyReplyError(400, 'signin required'); - } - - const user = await this.usersRepository.findOneByOrFail({ - host: IsNull(), - token: userToken, - }); - - const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - - delete profile.integrations.twitter; - - await this.userProfilesRepository.update(user.id, { - integrations: profile.integrations, - }); - - // Publish i updated event - this.globalEventService.publishMainStream(user.id, 'meUpdated', await this.userEntityService.pack(user, user, { - detail: true, - includeSecrets: true, - })); - - return 'Twitterã®é€£æºã‚’解除ã—ã¾ã—㟠:v:'; - }); - - const getTwAuth = async () => { - const meta = await this.metaService.fetch(true); - - if (meta.enableTwitterIntegration && meta.twitterConsumerKey && meta.twitterConsumerSecret) { - return autwh({ - consumerKey: meta.twitterConsumerKey, - consumerSecret: meta.twitterConsumerSecret, - callbackUrl: `${this.config.url}/api/tw/cb`, - }); - } else { - return null; - } - }; - - fastify.get('/connect/twitter', async (request, reply) => { - if (!this.compareOrigin(request)) { - throw new FastifyReplyError(400, 'invalid origin'); - } - - const userToken = this.getUserToken(request); - if (userToken == null) { - throw new FastifyReplyError(400, 'signin required'); - } - - const twAuth = await getTwAuth(); - const twCtx = await twAuth!.begin(); - this.redisClient.set(userToken, JSON.stringify(twCtx)); - reply.redirect(twCtx.url); - }); - - fastify.get('/signin/twitter', async (request, reply) => { - const twAuth = await getTwAuth(); - const twCtx = await twAuth!.begin(); - - const sessid = uuid(); - - this.redisClient.set(sessid, JSON.stringify(twCtx)); - - reply.setCookie('signin_with_twitter_sid', sessid, { - path: '/', - secure: this.config.url.startsWith('https'), - httpOnly: true, - }); - - reply.redirect(twCtx.url); - }); - - fastify.get('/tw/cb', async (request, reply) => { - const userToken = this.getUserToken(request); - - const twAuth = await getTwAuth(); - - if (userToken == null) { - const sessid = request.cookies['signin_with_twitter_sid']; - - if (sessid == null) { - throw new FastifyReplyError(400, 'invalid session'); - } - - const get = new Promise<any>((res, rej) => { - this.redisClient.get(sessid, async (_, twCtx) => { - res(twCtx); - }); - }); - - const twCtx = await get; - - const verifier = request.query.oauth_verifier; - if (!verifier || typeof verifier !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const result = await twAuth!.done(JSON.parse(twCtx), verifier); - - const link = await this.userProfilesRepository.createQueryBuilder() - .where('"integrations"->\'twitter\'->>\'userId\' = :id', { id: result.userId }) - .andWhere('"userHost" IS NULL') - .getOne(); - - if (link == null) { - throw new FastifyReplyError(404, `@${result.screenName}ã¨é€£æºã—ã¦ã„ã‚‹Misskeyアカウントã¯ã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸ...`); - } - - return this.signinService.signin(request, reply, await this.usersRepository.findOneBy({ id: link.userId }) as ILocalUser, true); - } else { - const verifier = request.query.oauth_verifier; - - if (!verifier || typeof verifier !== 'string') { - throw new FastifyReplyError(400, 'invalid session'); - } - - const get = new Promise<any>((res, rej) => { - this.redisClient.get(userToken, async (_, twCtx) => { - res(twCtx); - }); - }); - - const twCtx = await get; - - const result = await twAuth!.done(JSON.parse(twCtx), verifier); - - const user = await this.usersRepository.findOneByOrFail({ - host: IsNull(), - token: userToken, - }); - - const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); - - await this.userProfilesRepository.update(user.id, { - integrations: { - ...profile.integrations, - twitter: { - accessToken: result.accessToken, - accessTokenSecret: result.accessTokenSecret, - userId: result.userId, - screenName: result.screenName, - }, - }, - }); - - // Publish i updated event - this.globalEventService.publishMainStream(user.id, 'meUpdated', await this.userEntityService.pack(user, user, { - detail: true, - includeSecrets: true, - })); - - return `Twitter: @${result.screenName} ã‚’ã€Misskey: @${user.username} ã«æŽ¥ç¶šã—ã¾ã—ãŸï¼`; - } - }); - - done(); - } - - @bindThis - private getUserToken(request: FastifyRequest): string | null { - return ((request.headers['cookie'] ?? '').match(/igi=(\w+)/) ?? [null, null])[1]; - } - - @bindThis - private compareOrigin(request: FastifyRequest): boolean { - function normalizeUrl(url?: string): string { - return url ? url.endsWith('/') ? url.substr(0, url.length - 1) : url : ''; - } - - const referer = request.headers['referer']; - - return (normalizeUrl(referer) === normalizeUrl(this.config.url)); - } -} diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index d50d6c48ad874304c0359240638cbd7f4aad8ed9..cc1a7c4af50281beb497d597ececcf6a6b81ce23 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -40,11 +40,6 @@ </div> </div> </div> - <div class="social"> - <a v-if="meta && meta.enableTwitterIntegration" class="_borderButton _margin" :href="`${apiUrl}/signin/twitter`"><i class="ti ti-brand-twitter" style="margin-right: 4px;"></i>{{ $t('signinWith', { x: 'Twitter' }) }}</a> - <a v-if="meta && meta.enableGithubIntegration" class="_borderButton _margin" :href="`${apiUrl}/signin/github`"><i class="ti ti-brand-github" style="margin-right: 4px;"></i>{{ $t('signinWith', { x: 'GitHub' }) }}</a> - <a v-if="meta && meta.enableDiscordIntegration" class="_borderButton _margin" :href="`${apiUrl}/signin/discord`"><i class="ti ti-brand-discord" style="margin-right: 4px;"></i>{{ $t('signinWith', { x: 'Discord' }) }}</a> - </div> </form> </template> diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index 0166960ff656d43a637f605aa8512ecf08c9ceb4..9a07d3c959c8d9cbfaaebc1efe7066be71ed5c81 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -164,11 +164,6 @@ const menuDef = $computed(() => [{ text: i18n.ts.relays, to: '/admin/relays', active: currentPage?.route.name === 'relays', - }, { - icon: 'ti ti-share', - text: i18n.ts.integration, - to: '/admin/integrations', - active: currentPage?.route.name === 'integrations', }, { icon: 'ti ti-ban', text: i18n.ts.instanceBlocking, diff --git a/packages/frontend/src/pages/admin/integrations.discord.vue b/packages/frontend/src/pages/admin/integrations.discord.vue deleted file mode 100644 index 68ea040d7edbe8e86ee35f21ad04760237266d21..0000000000000000000000000000000000000000 --- a/packages/frontend/src/pages/admin/integrations.discord.vue +++ /dev/null @@ -1,60 +0,0 @@ -<template> -<FormSuspense :p="init"> - <div class="_gaps_m"> - <MkSwitch v-model="enableDiscordIntegration"> - <template #label>{{ i18n.ts.enable }}</template> - </MkSwitch> - - <template v-if="enableDiscordIntegration"> - <FormInfo>Callback URL: {{ `${uri}/api/dc/cb` }}</FormInfo> - - <MkInput v-model="discordClientId"> - <template #prefix><i class="ti ti-key"></i></template> - <template #label>Client ID</template> - </MkInput> - - <MkInput v-model="discordClientSecret"> - <template #prefix><i class="ti ti-key"></i></template> - <template #label>Client Secret</template> - </MkInput> - </template> - - <MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> - </div> -</FormSuspense> -</template> - -<script lang="ts" setup> -import { } from 'vue'; -import MkSwitch from '@/components/MkSwitch.vue'; -import MkInput from '@/components/MkInput.vue'; -import MkButton from '@/components/MkButton.vue'; -import FormInfo from '@/components/MkInfo.vue'; -import FormSuspense from '@/components/form/suspense.vue'; -import * as os from '@/os'; -import { fetchInstance } from '@/instance'; -import { i18n } from '@/i18n'; - -let uri: string = $ref(''); -let enableDiscordIntegration: boolean = $ref(false); -let discordClientId: string | null = $ref(null); -let discordClientSecret: string | null = $ref(null); - -async function init() { - const meta = await os.api('admin/meta'); - uri = meta.uri; - enableDiscordIntegration = meta.enableDiscordIntegration; - discordClientId = meta.discordClientId; - discordClientSecret = meta.discordClientSecret; -} - -function save() { - os.apiWithDialog('admin/update-meta', { - enableDiscordIntegration, - discordClientId, - discordClientSecret, - }).then(() => { - fetchInstance(); - }); -} -</script> diff --git a/packages/frontend/src/pages/admin/integrations.github.vue b/packages/frontend/src/pages/admin/integrations.github.vue deleted file mode 100644 index 2bd7852773aeba8d2571248f9e61545435b262e7..0000000000000000000000000000000000000000 --- a/packages/frontend/src/pages/admin/integrations.github.vue +++ /dev/null @@ -1,60 +0,0 @@ -<template> -<FormSuspense :p="init"> - <div class="_gaps_m"> - <MkSwitch v-model="enableGithubIntegration"> - <template #label>{{ i18n.ts.enable }}</template> - </MkSwitch> - - <template v-if="enableGithubIntegration"> - <FormInfo>Callback URL: {{ `${uri}/api/gh/cb` }}</FormInfo> - - <MkInput v-model="githubClientId"> - <template #prefix><i class="ti ti-key"></i></template> - <template #label>Client ID</template> - </MkInput> - - <MkInput v-model="githubClientSecret"> - <template #prefix><i class="ti ti-key"></i></template> - <template #label>Client Secret</template> - </MkInput> - </template> - - <MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> - </div> -</FormSuspense> -</template> - -<script lang="ts" setup> -import { } from 'vue'; -import MkSwitch from '@/components/MkSwitch.vue'; -import MkInput from '@/components/MkInput.vue'; -import MkButton from '@/components/MkButton.vue'; -import FormInfo from '@/components/MkInfo.vue'; -import FormSuspense from '@/components/form/suspense.vue'; -import * as os from '@/os'; -import { fetchInstance } from '@/instance'; -import { i18n } from '@/i18n'; - -let uri: string = $ref(''); -let enableGithubIntegration: boolean = $ref(false); -let githubClientId: string | null = $ref(null); -let githubClientSecret: string | null = $ref(null); - -async function init() { - const meta = await os.api('admin/meta'); - uri = meta.uri; - enableGithubIntegration = meta.enableGithubIntegration; - githubClientId = meta.githubClientId; - githubClientSecret = meta.githubClientSecret; -} - -function save() { - os.apiWithDialog('admin/update-meta', { - enableGithubIntegration, - githubClientId, - githubClientSecret, - }).then(() => { - fetchInstance(); - }); -} -</script> diff --git a/packages/frontend/src/pages/admin/integrations.twitter.vue b/packages/frontend/src/pages/admin/integrations.twitter.vue deleted file mode 100644 index aa658336634674fa9267a981ce8eee90ffc3201e..0000000000000000000000000000000000000000 --- a/packages/frontend/src/pages/admin/integrations.twitter.vue +++ /dev/null @@ -1,60 +0,0 @@ -<template> -<FormSuspense :p="init"> - <div class="_gaps_m"> - <MkSwitch v-model="enableTwitterIntegration"> - <template #label>{{ i18n.ts.enable }}</template> - </MkSwitch> - - <template v-if="enableTwitterIntegration"> - <FormInfo>Callback URL: {{ `${uri}/api/tw/cb` }}</FormInfo> - - <MkInput v-model="twitterConsumerKey"> - <template #prefix><i class="ti ti-key"></i></template> - <template #label>Consumer Key</template> - </MkInput> - - <MkInput v-model="twitterConsumerSecret"> - <template #prefix><i class="ti ti-key"></i></template> - <template #label>Consumer Secret</template> - </MkInput> - </template> - - <MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> - </div> -</FormSuspense> -</template> - -<script lang="ts" setup> -import { defineComponent } from 'vue'; -import MkSwitch from '@/components/MkSwitch.vue'; -import MkInput from '@/components/MkInput.vue'; -import MkButton from '@/components/MkButton.vue'; -import FormInfo from '@/components/MkInfo.vue'; -import FormSuspense from '@/components/form/suspense.vue'; -import * as os from '@/os'; -import { fetchInstance } from '@/instance'; -import { i18n } from '@/i18n'; - -let uri: string = $ref(''); -let enableTwitterIntegration: boolean = $ref(false); -let twitterConsumerKey: string | null = $ref(null); -let twitterConsumerSecret: string | null = $ref(null); - -async function init() { - const meta = await os.api('admin/meta'); - uri = meta.uri; - enableTwitterIntegration = meta.enableTwitterIntegration; - twitterConsumerKey = meta.twitterConsumerKey; - twitterConsumerSecret = meta.twitterConsumerSecret; -} - -function save() { - os.apiWithDialog('admin/update-meta', { - enableTwitterIntegration, - twitterConsumerKey, - twitterConsumerSecret, - }).then(() => { - fetchInstance(); - }); -} -</script> diff --git a/packages/frontend/src/pages/admin/integrations.vue b/packages/frontend/src/pages/admin/integrations.vue deleted file mode 100644 index 6888a492f6bf8fa8ede5beb932d52e5235e50166..0000000000000000000000000000000000000000 --- a/packages/frontend/src/pages/admin/integrations.vue +++ /dev/null @@ -1,61 +0,0 @@ -<template> -<MkStickyContainer> - <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> - <FormSuspense :p="init"> - <div class="_gaps_m"> - <MkFolder> - <template #icon><i class="ti ti-brand-twitter"></i></template> - <template #label>Twitter</template> - <template #suffix>{{ enableTwitterIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template> - <XTwitter/> - </MkFolder> - <MkFolder> - <template #icon><i class="ti ti-brand-github"></i></template> - <template #label>GitHub</template> - <template #suffix>{{ enableGithubIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template> - <XGithub/> - </MkFolder> - <MkFolder> - <template #icon><i class="ti ti-brand-discord"></i></template> - <template #label>Discord</template> - <template #suffix>{{ enableDiscordIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template> - <XDiscord/> - </MkFolder> - </div> - </FormSuspense> - </MkSpacer> -</MkStickyContainer> -</template> - -<script lang="ts" setup> -import { } from 'vue'; -import XTwitter from './integrations.twitter.vue'; -import XGithub from './integrations.github.vue'; -import XDiscord from './integrations.discord.vue'; -import FormSuspense from '@/components/form/suspense.vue'; -import MkFolder from '@/components/MkFolder.vue'; -import * as os from '@/os'; -import { i18n } from '@/i18n'; -import { definePageMetadata } from '@/scripts/page-metadata'; - -let enableTwitterIntegration: boolean = $ref(false); -let enableGithubIntegration: boolean = $ref(false); -let enableDiscordIntegration: boolean = $ref(false); - -async function init() { - const meta = await os.api('admin/meta'); - enableTwitterIntegration = meta.enableTwitterIntegration; - enableGithubIntegration = meta.enableGithubIntegration; - enableDiscordIntegration = meta.enableDiscordIntegration; -} - -const headerActions = $computed(() => []); - -const headerTabs = $computed(() => []); - -definePageMetadata({ - title: i18n.ts.integration, - icon: 'ti ti-share', -}); -</script> diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index 4dbc6ec74c184643bde6539345eb880f19920d45..8631f3e341bf04391c03704672d2054c6220b4af 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -89,11 +89,6 @@ const menuDef = computed(() => [{ text: i18n.ts.email, to: '/settings/email', active: currentPage?.route.name === 'email', - }, { - icon: 'ti ti-share', - text: i18n.ts.integration, - to: '/settings/integration', - active: currentPage?.route.name === 'integration', }, { icon: 'ti ti-lock', text: i18n.ts.security, diff --git a/packages/frontend/src/pages/settings/integration.vue b/packages/frontend/src/pages/settings/integration.vue deleted file mode 100644 index 1e5a785465b4c57ebd7f972dcc424d0893359ce0..0000000000000000000000000000000000000000 --- a/packages/frontend/src/pages/settings/integration.vue +++ /dev/null @@ -1,99 +0,0 @@ -<template> -<div class="_gaps_m"> - <FormSection v-if="instance.enableTwitterIntegration"> - <template #label><i class="ti ti-brand-twitter"></i> Twitter</template> - <p v-if="integrations.twitter">{{ i18n.ts.connectedTo }}: <a :href="`https://twitter.com/${integrations.twitter.screenName}`" rel="nofollow noopener" target="_blank">@{{ integrations.twitter.screenName }}</a></p> - <MkButton v-if="integrations.twitter" danger @click="disconnectTwitter">{{ i18n.ts.disconnectService }}</MkButton> - <MkButton v-else primary @click="connectTwitter">{{ i18n.ts.connectService }}</MkButton> - </FormSection> - - <FormSection v-if="instance.enableDiscordIntegration"> - <template #label><i class="ti ti-brand-discord"></i> Discord</template> - <p v-if="integrations.discord">{{ i18n.ts.connectedTo }}: <a :href="`https://discord.com/users/${integrations.discord.id}`" rel="nofollow noopener" target="_blank">@{{ integrations.discord.username }}#{{ integrations.discord.discriminator }}</a></p> - <MkButton v-if="integrations.discord" danger @click="disconnectDiscord">{{ i18n.ts.disconnectService }}</MkButton> - <MkButton v-else primary @click="connectDiscord">{{ i18n.ts.connectService }}</MkButton> - </FormSection> - - <FormSection v-if="instance.enableGithubIntegration"> - <template #label><i class="ti ti-brand-github"></i> GitHub</template> - <p v-if="integrations.github">{{ i18n.ts.connectedTo }}: <a :href="`https://github.com/${integrations.github.login}`" rel="nofollow noopener" target="_blank">@{{ integrations.github.login }}</a></p> - <MkButton v-if="integrations.github" danger @click="disconnectGithub">{{ i18n.ts.disconnectService }}</MkButton> - <MkButton v-else primary @click="connectGithub">{{ i18n.ts.connectService }}</MkButton> - </FormSection> -</div> -</template> - -<script lang="ts" setup> -import { computed, onMounted, ref, watch } from 'vue'; -import { apiUrl } from '@/config'; -import FormSection from '@/components/form/section.vue'; -import MkButton from '@/components/MkButton.vue'; -import { $i } from '@/account'; -import { instance } from '@/instance'; -import { i18n } from '@/i18n'; -import { definePageMetadata } from '@/scripts/page-metadata'; - -const twitterForm = ref<Window | null>(null); -const discordForm = ref<Window | null>(null); -const githubForm = ref<Window | null>(null); - -const integrations = computed(() => $i!.integrations); - -function openWindow(service: string, type: string) { - return window.open(`${apiUrl}/${type}/${service}`, - `${service}_${type}_window`, - 'height=570, width=520', - ); -} - -function connectTwitter() { - twitterForm.value = openWindow('twitter', 'connect'); -} - -function disconnectTwitter() { - openWindow('twitter', 'disconnect'); -} - -function connectDiscord() { - discordForm.value = openWindow('discord', 'connect'); -} - -function disconnectDiscord() { - openWindow('discord', 'disconnect'); -} - -function connectGithub() { - githubForm.value = openWindow('github', 'connect'); -} - -function disconnectGithub() { - openWindow('github', 'disconnect'); -} - -onMounted(() => { - document.cookie = `igi=${$i!.token}; path=/;` + - ' max-age=31536000;' + - (document.location.protocol.startsWith('https') ? ' secure' : ''); - - watch(integrations, () => { - if (integrations.value.twitter) { - if (twitterForm.value) twitterForm.value.close(); - } - if (integrations.value.discord) { - if (discordForm.value) discordForm.value.close(); - } - if (integrations.value.github) { - if (githubForm.value) githubForm.value.close(); - } - }); -}); - -const headerActions = $computed(() => []); - -const headerTabs = $computed(() => []); - -definePageMetadata({ - title: i18n.ts.integration, - icon: 'ti ti-share', -}); -</script> diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index 22106e1595d4f7a936c428cfbcf949278f289e3d..595b1f622aacb69b63f012554e444a0252190a3f 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -70,10 +70,6 @@ export const routes = [{ path: '/email', name: 'email', component: page(() => import('./pages/settings/email.vue')), - }, { - path: '/integration', - name: 'integration', - component: page(() => import('./pages/settings/integration.vue')), }, { path: '/security', name: 'security', @@ -399,10 +395,6 @@ export const routes = [{ path: '/relays', name: 'relays', component: page(() => import('./pages/admin/relays.vue')), - }, { - path: '/integrations', - name: 'integrations', - component: page(() => import('./pages/admin/integrations.vue')), }, { path: '/instance-block', name: 'instance-block',