fix: various fixes to sentry-reported errors and more
This commit is contained in:
@@ -17,8 +17,9 @@
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {BlueskyCallbackResult} from '@fluxer/api/src/bluesky/IBlueskyOAuthService';
|
||||
import type {BlueskyAuthorizeResult, BlueskyCallbackResult} from '@fluxer/api/src/bluesky/IBlueskyOAuthService';
|
||||
import {Config} from '@fluxer/api/src/Config';
|
||||
import {BlueskyOAuthAuthorizationFailedError} from '@fluxer/api/src/connection/errors/BlueskyOAuthAuthorizationFailedError';
|
||||
import {BlueskyOAuthCallbackFailedError} from '@fluxer/api/src/connection/errors/BlueskyOAuthCallbackFailedError';
|
||||
import {BlueskyOAuthNotEnabledError} from '@fluxer/api/src/connection/errors/BlueskyOAuthNotEnabledError';
|
||||
import {BlueskyOAuthStateInvalidError} from '@fluxer/api/src/connection/errors/BlueskyOAuthStateInvalidError';
|
||||
@@ -36,6 +37,15 @@ import {
|
||||
BlueskyAuthorizeResponse,
|
||||
} from '@fluxer/schema/src/domains/connection/BlueskyOAuthSchemas';
|
||||
|
||||
const BLUESKY_PROFILE_URL_RE = /^https?:\/\/bsky\.app\/profile\//i;
|
||||
|
||||
function normalizeBlueskyHandle(input: string): string {
|
||||
let handle = input.trim();
|
||||
handle = handle.replace(BLUESKY_PROFILE_URL_RE, '');
|
||||
handle = handle.replace(/^@/, '');
|
||||
return handle;
|
||||
}
|
||||
|
||||
export function BlueskyOAuthController(app: HonoApp) {
|
||||
app.get('/connections/bluesky/client-metadata.json', async (ctx) => {
|
||||
const service = ctx.get('blueskyOAuthService');
|
||||
@@ -73,8 +83,9 @@ export function BlueskyOAuthController(app: HonoApp) {
|
||||
if (!service) {
|
||||
throw new BlueskyOAuthNotEnabledError();
|
||||
}
|
||||
const {handle} = ctx.req.valid('json');
|
||||
const {handle: rawHandle} = ctx.req.valid('json');
|
||||
const userId = ctx.get('user').id;
|
||||
const handle = normalizeBlueskyHandle(rawHandle);
|
||||
|
||||
const connectionService = ctx.get('connectionService');
|
||||
const connections = await connectionService.getConnectionsForUser(userId);
|
||||
@@ -86,7 +97,13 @@ export function BlueskyOAuthController(app: HonoApp) {
|
||||
throw new ConnectionAlreadyExistsError();
|
||||
}
|
||||
|
||||
const result = await service.authorize(handle, userId);
|
||||
let result: BlueskyAuthorizeResult;
|
||||
try {
|
||||
result = await service.authorize(handle, userId);
|
||||
} catch (error) {
|
||||
Logger.error({error, handle}, 'Bluesky OAuth authorize failed');
|
||||
throw new BlueskyOAuthAuthorizationFailedError();
|
||||
}
|
||||
return ctx.json({authorize_url: result.authorizeUrl});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ export class BlueskyOAuthService implements IBlueskyOAuthService {
|
||||
clientMetadata: {
|
||||
client_id: `${baseUrl}/connections/bluesky/client-metadata.json`,
|
||||
client_name: config.client_name,
|
||||
client_uri: config.client_uri || baseUrl,
|
||||
client_uri: baseUrl,
|
||||
logo_uri: config.logo_uri || undefined,
|
||||
tos_uri: config.tos_uri || undefined,
|
||||
policy_uri: config.policy_uri || undefined,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import {createTestAccount} from '@fluxer/api/src/auth/tests/AuthTestUtils';
|
||||
import {createUserID} from '@fluxer/api/src/BrandedTypes';
|
||||
import {
|
||||
createBlueskyConnectionViaOAuth,
|
||||
createBlueskyDid,
|
||||
createBlueskyHandle,
|
||||
listConnections,
|
||||
@@ -122,6 +123,69 @@ describe('Bluesky OAuth', () => {
|
||||
const callArgs = harness.mockBlueskyOAuthService.authorizeSpy.mock.calls[0];
|
||||
expect(callArgs[0]).toBe(handle);
|
||||
});
|
||||
|
||||
it('normalises a bsky.app profile URL to a handle', async () => {
|
||||
const account = await createTestAccount(harness);
|
||||
|
||||
await createBuilder(harness, account.token)
|
||||
.post('/users/@me/connections/bluesky/authorize')
|
||||
.body({handle: 'https://bsky.app/profile/alice.bsky.social'})
|
||||
.expect(200)
|
||||
.execute();
|
||||
|
||||
expect(harness.mockBlueskyOAuthService.authorizeSpy).toHaveBeenCalledTimes(1);
|
||||
expect(harness.mockBlueskyOAuthService.authorizeSpy.mock.calls[0][0]).toBe('alice.bsky.social');
|
||||
});
|
||||
|
||||
it('normalises an http bsky.app profile URL to a handle', async () => {
|
||||
const account = await createTestAccount(harness);
|
||||
|
||||
await createBuilder(harness, account.token)
|
||||
.post('/users/@me/connections/bluesky/authorize')
|
||||
.body({handle: 'http://bsky.app/profile/someone.bsky.social'})
|
||||
.expect(200)
|
||||
.execute();
|
||||
|
||||
expect(harness.mockBlueskyOAuthService.authorizeSpy.mock.calls[0][0]).toBe('someone.bsky.social');
|
||||
});
|
||||
|
||||
it('strips leading @ from handle', async () => {
|
||||
const account = await createTestAccount(harness);
|
||||
|
||||
await createBuilder(harness, account.token)
|
||||
.post('/users/@me/connections/bluesky/authorize')
|
||||
.body({handle: '@alice.bsky.social'})
|
||||
.expect(200)
|
||||
.execute();
|
||||
|
||||
expect(harness.mockBlueskyOAuthService.authorizeSpy.mock.calls[0][0]).toBe('alice.bsky.social');
|
||||
});
|
||||
|
||||
it('detects duplicate after normalising profile URL', async () => {
|
||||
const account = await createTestAccount(harness);
|
||||
const handle = createBlueskyHandle('testuser');
|
||||
const did = createBlueskyDid('testuser');
|
||||
const userId = createUserID(BigInt(account.userId));
|
||||
|
||||
await createBlueskyConnectionViaOAuth(harness, account.token, handle, did, userId);
|
||||
|
||||
await createBuilder(harness, account.token)
|
||||
.post('/users/@me/connections/bluesky/authorize')
|
||||
.body({handle: `https://bsky.app/profile/${handle}`})
|
||||
.expect(HTTP_STATUS.CONFLICT, APIErrorCodes.CONNECTION_ALREADY_EXISTS)
|
||||
.execute();
|
||||
});
|
||||
|
||||
it('returns BLUESKY_OAUTH_AUTHORIZATION_FAILED when authorize throws', async () => {
|
||||
const account = await createTestAccount(harness);
|
||||
harness.mockBlueskyOAuthService.configure({shouldFailAuthorize: true});
|
||||
|
||||
await createBuilder(harness, account.token)
|
||||
.post('/users/@me/connections/bluesky/authorize')
|
||||
.body({handle: 'invalid-handle'})
|
||||
.expect(HTTP_STATUS.BAD_REQUEST, APIErrorCodes.BLUESKY_OAUTH_AUTHORIZATION_FAILED)
|
||||
.execute();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /connections/bluesky/callback', () => {
|
||||
|
||||
Reference in New Issue
Block a user