From b7ffa05848daa72365f329dcab4bf4bfabf12730 Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 1 Mar 2023 21:37:49 -0500 Subject: [PATCH 1/6] Enable multipart for masto oauth endpoints to fix Ivory --- packages/backend/src/server/index.ts | 15 +++++++++------ packages/client/src/pages/auth.vue | 5 ++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 6f7dcfd39..92f1c549d 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -78,6 +78,7 @@ const mastoRouter = new Router(); mastoRouter.use( koaBody({ urlencoded: true, + multipart: true, }), ); @@ -171,6 +172,7 @@ mastoRouter.get("/oauth/authorize", async (ctx) => { mastoRouter.post("/oauth/token", async (ctx) => { const body: any = ctx.request.body || ctx.request.query; console.log('token-request', body) + console.log('token-query', ctx.request.query) let client_id: any = ctx.request.query.client_id; const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; const generator = (megalodon as any).default; @@ -178,13 +180,14 @@ mastoRouter.post("/oauth/token", async (ctx) => { let m = null; let token = null; if (body.code) { - m = body.code.match(/^([a-zA-Z0-9]{8})([a-zA-Z0-9]{4})([a-zA-Z0-9]{4})([a-zA-Z0-9]{4})([a-zA-Z0-9]{12})/); - if (!m.length) { - ctx.body = { error: "Invalid code" }; - return; - } - token = `${m[1]}-${m[2]}-${m[3]}-${m[4]}-${m[5]}` + //m = body.code.match(/^([a-zA-Z0-9]{8})([a-zA-Z0-9]{4})([a-zA-Z0-9]{4})([a-zA-Z0-9]{4})([a-zA-Z0-9]{12})/); + //if (!m.length) { + // ctx.body = { error: "Invalid code" }; + // return; + //} + //token = `${m[1]}-${m[2]}-${m[3]}-${m[4]}-${m[5]}` console.log(body.code, token) + token = body.code } if (client_id instanceof Array) { client_id = client_id.toString(); diff --git a/packages/client/src/pages/auth.vue b/packages/client/src/pages/auth.vue index b7ea082c6..2b4c67ba7 100644 --- a/packages/client/src/pages/auth.vue +++ b/packages/client/src/pages/auth.vue @@ -88,11 +88,10 @@ export default defineComponent({ const getUrlParams = () => window.location.search.substring(1).split('&').reduce((result, query) => { const [k, v] = query.split('='); result[k] = decodeURI(v); return result; }, {}); const isMastodon = !!getUrlParams().mastodon if (this.session.app.callbackUrl && isMastodon) { - const state = getUrlParams().state - const stateParam = `&state=${state}` + const stateParam = !!getUrlParams().state ? `&state=$(getUrlParams().state)` : ''; const tokenRaw = this.session.token const token = tokenRaw.replaceAll('-', '') - location.href = `${this.session.app.callbackUrl}?code=${token}${stateParam}`; + location.href = `${this.session.app.callbackUrl}?code=${tokenRaw}${stateParam}`; } else if (this.session.app.callbackUrl) { const url = new URL(this.session.app.callbackUrl); if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(url.protocol)) throw new Error('invalid url'); From e2ebe83238e02fe9a48e9590b6aa765185495115 Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 1 Mar 2023 23:45:34 -0500 Subject: [PATCH 2/6] Convert limit parameter to int for certain Mastodon account endpoints --- .../backend/src/server/api/mastodon/endpoints/account.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index 312e38135..3e9da5750 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -42,6 +42,7 @@ export function apiAccountMastodon(router: Router): void { sensitive: false, language: "", }; + console.log(acct); ctx.body = acct; } catch (e: any) { console.error(e); @@ -126,7 +127,7 @@ export function apiAccountMastodon(router: Router): void { try { const data = await client.getAccountFollowers( ctx.params.id, - ctx.query as any, + limitToInt(ctx.query as any), ); ctx.body = data.data; } catch (e: any) { @@ -146,7 +147,7 @@ export function apiAccountMastodon(router: Router): void { try { const data = await client.getAccountFollowing( ctx.params.id, - ctx.query as any, + limitToInt(ctx.query as any), ); ctx.body = data.data; } catch (e: any) { From 5e79069c4a7ee8ad81012534272d1b5e26f8aabf Mon Sep 17 00:00:00 2001 From: Luna Date: Thu, 2 Mar 2023 17:21:14 -0500 Subject: [PATCH 3/6] Clean up auth.vue --- packages/client/src/pages/auth.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/client/src/pages/auth.vue b/packages/client/src/pages/auth.vue index 2b4c67ba7..4ad7d08c6 100644 --- a/packages/client/src/pages/auth.vue +++ b/packages/client/src/pages/auth.vue @@ -89,9 +89,7 @@ export default defineComponent({ const isMastodon = !!getUrlParams().mastodon if (this.session.app.callbackUrl && isMastodon) { const stateParam = !!getUrlParams().state ? `&state=$(getUrlParams().state)` : ''; - const tokenRaw = this.session.token - const token = tokenRaw.replaceAll('-', '') - location.href = `${this.session.app.callbackUrl}?code=${tokenRaw}${stateParam}`; + location.href = `${this.session.app.callbackUrl}?code=${this.session.token}${stateParam}`; } else if (this.session.app.callbackUrl) { const url = new URL(this.session.app.callbackUrl); if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(url.protocol)) throw new Error('invalid url'); From c81d6ecc1e8996c01e89a1daef8865ddb1952bdc Mon Sep 17 00:00:00 2001 From: Luna Date: Thu, 2 Mar 2023 22:29:28 -0500 Subject: [PATCH 4/6] Proxy object IDs for Mastodon API to prevent Calckey ID format incompatibilities --- packages/backend/src/server/api/index.ts | 26 +++ .../server/api/mastodon/endpoints/account.ts | 170 +++++++++++++----- 2 files changed, 151 insertions(+), 45 deletions(-) diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts index 96b03a4f6..aa6507743 100644 --- a/packages/backend/src/server/api/index.ts +++ b/packages/backend/src/server/api/index.ts @@ -22,6 +22,32 @@ import github from "./service/github.js"; import twitter from "./service/twitter.js"; import { koaBody } from "koa-body"; +export enum IdType { + CalckeyId, + MastodonId +}; + +export function convertId(idIn: string, idConvertTo: IdType ) { + let idArray = [] + switch (idConvertTo) { + case IdType.CalckeyId: + idArray = [...idIn].map(item => item.charCodeAt(0)); + idArray = idArray.map(item => { + if (item.toString().length < 3) { + return `0${item.toString()}` + } + else return item.toString() + }); + return idArray.join(''); + case IdType.MastodonId: + for (let i = 0; i < idIn.length; i += 3) { + idArray.push(idIn.slice(i, i+3)); + } + idArray = idArray.map(item => String.fromCharCode(item)); + return idArray.join(''); + } +}; + // Init app const app = new Koa(); diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts index 3e9da5750..1c5e31fe8 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/account.ts @@ -4,8 +4,9 @@ import Router from "@koa/router"; import { FindOptionsWhere, IsNull } from "typeorm"; import { getClient } from "../ApiMastodonCompatibleService.js"; import { argsToBools, limitToInt } from "./timeline.js"; +import { convertId, IdType } from "../../index.js"; -const relationshopModel = { +const relationshipModel = { id: "", following: false, followed_by: false, @@ -29,7 +30,8 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.verifyAccountCredentials(); - const acct = data.data; + let acct = data.data; + acct.id = convertId(acct.id, IdType.MastodonId); acct.url = `${BASE_URL}/@${acct.url}`; acct.note = ""; acct.avatar_static = acct.avatar; @@ -59,7 +61,9 @@ export function apiAccountMastodon(router: Router): void { const data = await client.updateCredentials( (ctx.request as any).body as any, ); - ctx.body = data.data; + let resp = data.data; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -72,8 +76,10 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.search((request.query as any).acct, 'accounts'); - ctx.body = data.data.accounts[0]; + const data = await client.search((ctx.request.query as any).acct, 'accounts'); + let resp = data.data.accounts[0]; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -88,8 +94,11 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.getAccount(ctx.params.id); - ctx.body = data.data; + const calcId = convertId(ctx.params.id, IdType.CalckeyId); + const data = await client.getAccount(calcId); + let resp = data.data; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -106,10 +115,20 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountStatuses( - ctx.params.id, + convertId(ctx.params.id, IdType.CalckeyId), argsToBools(limitToInt(ctx.query as any)), ); - ctx.body = data.data; + let resp = data.data; + for (let statIdx = 0; statIdx < resp.length; statIdx++) { + resp[statIdx].id = convertId(resp[statIdx].id, IdType.MastodonId); + resp[statIdx].in_reply_to_account_id = resp[statIdx].in_reply_to_account_id ? convertId(resp[statIdx].in_reply_to_account_id, IdType.MastodonId) : null; + resp[statIdx].in_reply_to_id = resp[statIdx].in_reply_to_id ? convertId(resp[statIdx].in_reply_to_id, IdType.MastodonId) : null; + let mentions = resp[statIdx].mentions + for (let mtnIdx = 0; mtnIdx < mentions.length; mtnIdx++) { + resp[statIdx].mentions[mtnIdx].id = convertId(mentions[mtnIdx].id, IdType.MastodonId); + } + } + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -126,10 +145,14 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountFollowers( - ctx.params.id, + convertId(ctx.params.id, IdType.CalckeyId), limitToInt(ctx.query as any), ); - ctx.body = data.data; + let resp = data.data; + for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) { + resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId); + } + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -146,10 +169,14 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getAccountFollowing( - ctx.params.id, + convertId(ctx.params.id, IdType.CalckeyId), limitToInt(ctx.query as any), ); - ctx.body = data.data; + let resp = data.data; + for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) { + resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId); + } + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -182,10 +209,11 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.followAccount(ctx.params.id); - const acct = data.data; + const data = await client.followAccount(convertId(ctx.params.id, IdType.CalckeyId)); + let acct = data.data; acct.following = true; - ctx.body = data.data; + acct.id = convertId(acct.id, IdType.MastodonId); + ctx.body = acct; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -201,10 +229,11 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unfollowAccount(ctx.params.id); - const acct = data.data; + const data = await client.unfollowAccount(convertId(ctx.params.id, IdType.CalckeyId)); + let acct = data.data; + acct.id = convertId(acct.id, IdType.MastodonId); acct.following = false; - ctx.body = data.data; + ctx.body = acct; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -220,8 +249,10 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.blockAccount(ctx.params.id); - ctx.body = data.data; + const data = await client.blockAccount(convertId(ctx.params.id, IdType.CalckeyId)); + let resp = data.data; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -237,8 +268,10 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unblockAccount(ctx.params.id); - ctx.body = data.data; + const data = await client.unblockAccount(convertId(ctx.params.id, IdType.MastodonId)); + let resp = data.data; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -255,10 +288,12 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.muteAccount( - ctx.params.id, + convertId(ctx.params.id, IdType.CalckeyId), (ctx.request as any).body as any, ); - ctx.body = data.data; + let resp = data.data; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -274,8 +309,10 @@ export function apiAccountMastodon(router: Router): void { const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unmuteAccount(ctx.params.id); - ctx.body = data.data; + const data = await client.unmuteAccount(convertId(ctx.params.id, IdType.CalckeyId)); + let resp = data.data; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -291,16 +328,23 @@ export function apiAccountMastodon(router: Router): void { let users; try { // TODO: this should be body - const idsRaw = ctx.request.query ? ctx.request.query["id[]"] : null; - const ids = typeof idsRaw === "string" ? [idsRaw] : idsRaw; + let ids = ctx.request.query ? ctx.request.query["id[]"] : null; + if (typeof ids === "string") { + ids = [ids]; + } users = ids; - relationshopModel.id = idsRaw?.toString() || "1"; - if (!idsRaw) { - ctx.body = [relationshopModel]; + relationshipModel.id = ids?.toString() || "1"; + if (!ids) { + ctx.body = [relationshipModel]; return; } + const data = await client.getRelationships(ids); - ctx.body = data.data; + let resp = data.data; + for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) { + resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId); + } + ctx.body = resp; } catch (e: any) { console.error(e); let data = e.response.data; @@ -316,7 +360,17 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = (await client.getBookmarks(ctx.query as any)) as any; - ctx.body = data.data; + let resp = data.data; + for (let statIdx = 0; statIdx < resp.length; statIdx++) { + resp[statIdx].id = convertId(resp[statIdx].id, IdType.MastodonId); + resp[statIdx].in_reply_to_account_id = resp[statIdx].in_reply_to_account_id ? convertId(resp[statIdx].in_reply_to_account_id, IdType.MastodonId) : null; + resp[statIdx].in_reply_to_id = resp[statIdx].in_reply_to_id ? convertId(resp[statIdx].in_reply_to_id, IdType.MastodonId) : null; + let mentions = resp[statIdx].mentions + for (let mtnIdx = 0; mtnIdx < mentions.length; mtnIdx++) { + resp[statIdx].mentions[mtnIdx].id = convertId(mentions[mtnIdx].id, IdType.MastodonId); + } + } + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -330,7 +384,17 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getFavourites(ctx.query as any); - ctx.body = data.data; + let resp = data.data; + for (let statIdx = 0; statIdx < resp.length; statIdx++) { + resp[statIdx].id = convertId(resp[statIdx].id, IdType.MastodonId); + resp[statIdx].in_reply_to_account_id = resp[statIdx].in_reply_to_account_id ? convertId(resp[statIdx].in_reply_to_account_id, IdType.MastodonId) : null; + resp[statIdx].in_reply_to_id = resp[statIdx].in_reply_to_id ? convertId(resp[statIdx].in_reply_to_id, IdType.MastodonId) : null; + let mentions = resp[statIdx].mentions + for (let mtnIdx = 0; mtnIdx < mentions.length; mtnIdx++) { + resp[statIdx].mentions[mtnIdx].id = convertId(mentions[mtnIdx].id, IdType.MastodonId); + } + } + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -344,7 +408,11 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getMutes(ctx.query as any); - ctx.body = data.data; + let resp = data.data; + for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) { + resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId); + } + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -358,7 +426,11 @@ export function apiAccountMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const data = await client.getBlocks(ctx.query as any); - ctx.body = data.data; + let resp = data.data; + for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) { + resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId); + } + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -366,7 +438,7 @@ export function apiAccountMastodon(router: Router): void { ctx.body = e.response.data; } }); - router.get("/v1/follow_ctxs", async (ctx) => { + router.get("/v1/follow_requests", async (ctx) => { const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); @@ -374,7 +446,11 @@ export function apiAccountMastodon(router: Router): void { const data = await client.getFollowRequests( ((ctx.query as any) || { limit: 20 }).limit, ); - ctx.body = data.data; + let resp = data.data; + for (let acctIdx = 0; acctIdx < resp.length; acctIdx++) { + resp[acctIdx].id = convertId(resp[acctIdx].id, IdType.MastodonId); + } + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -383,14 +459,16 @@ export function apiAccountMastodon(router: Router): void { } }); router.post<{ Params: { id: string } }>( - "/v1/follow_ctxs/:id/authorize", + "/v1/follow_requests/:id/authorize", async (ctx) => { const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.acceptFollowRequest(ctx.params.id); - ctx.body = data.data; + const data = await client.acceptFollowRequest(convertId(ctx.params.id, IdType.CalckeyId)); + let resp = data.data; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); @@ -400,14 +478,16 @@ export function apiAccountMastodon(router: Router): void { }, ); router.post<{ Params: { id: string } }>( - "/v1/follow_ctxs/:id/reject", + "/v1/follow_requests/:id/reject", async (ctx) => { const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); try { - const data = await client.rejectFollowRequest(ctx.params.id); - ctx.body = data.data; + const data = await client.rejectFollowRequest(convertId(ctx.params.id, IdType.CalckeyId)); + let resp = data.data; + resp.id = convertId(resp.id, IdType.MastodonId); + ctx.body = resp; } catch (e: any) { console.error(e); console.error(e.response.data); From 7236aa4a3a90ae906f86b58a192991947fca67b7 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 11 Mar 2023 23:02:41 -0500 Subject: [PATCH 5/6] Sorta kinda handle client_credentials auth flow --- packages/backend/src/server/index.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 92f1c549d..174aaf222 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -31,6 +31,7 @@ import webServer from "./web/index.js"; import { initializeStreamingServer } from "./api/streaming.js"; import { koaBody } from "koa-body"; import removeTrailingSlash from "koa-remove-trailing-slashes"; +import {v4 as uuid} from "uuid"; export const serverLogger = new Logger("server", "gray", false); @@ -171,9 +172,19 @@ mastoRouter.get("/oauth/authorize", async (ctx) => { mastoRouter.post("/oauth/token", async (ctx) => { const body: any = ctx.request.body || ctx.request.query; - console.log('token-request', body) - console.log('token-query', ctx.request.query) - let client_id: any = ctx.request.query.client_id; + console.log('token-request', body); + console.log('token-query', ctx.request.query); + if (body.redirect_uri.startsWith('com.tapbots') && body.grant_type === 'client_credentials') { + const ret = { + access_token: uuid(), + token_type: "Bearer", + scope: "read", + created_at: Math.floor(new Date().getTime() / 1000), + }; + ctx.body = ret; + return; + } + let client_id: any = body.client_id; const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; const generator = (megalodon as any).default; const client = generator("misskey", BASE_URL, null) as MegalodonInterface; From e198a34cd0e2cf3bd8c1a78bc1327a8ae69343f1 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 13 Mar 2023 00:44:38 -0400 Subject: [PATCH 6/6] Small fix to Masto ID conversion code --- packages/backend/src/server/api/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts index aa6507743..4eb87a614 100644 --- a/packages/backend/src/server/api/index.ts +++ b/packages/backend/src/server/api/index.ts @@ -30,7 +30,7 @@ export enum IdType { export function convertId(idIn: string, idConvertTo: IdType ) { let idArray = [] switch (idConvertTo) { - case IdType.CalckeyId: + case IdType.MastodonId: idArray = [...idIn].map(item => item.charCodeAt(0)); idArray = idArray.map(item => { if (item.toString().length < 3) { @@ -39,8 +39,11 @@ export function convertId(idIn: string, idConvertTo: IdType ) { else return item.toString() }); return idArray.join(''); - case IdType.MastodonId: + case IdType.CalckeyId: for (let i = 0; i < idIn.length; i += 3) { + if ((idIn.length % 3) !== 0) { + idIn = `0${idIn}` + } idArray.push(idIn.slice(i, i+3)); } idArray = idArray.map(item => String.fromCharCode(item));