From 9bfe429c0b9b1f270b2035fda03da84db9f057d2 Mon Sep 17 00:00:00 2001 From: askmeaboutlo0m Date: Mon, 11 Nov 2024 14:00:32 +0100 Subject: [PATCH 1/3] Fix Bsky login check (#382) * Handle Bluesky login check without credentials It accessed undefined data and fell on its face, now it returns successfully with loggedIn set to false. * Do Bluesky login check in electron-app only After rebasing to the main repository's develop branch, Bluesky login in the UI is suddenly failing with some kind of garbage "url must be a string not an object" error when we aren't passing any such parameter in the first place. I don't know what that's about, but doing it in electron-app works fine, so I changed the UI code to defer to that instead. This also improves the error messages so that the user isn't left with the page seemingly not reacting to their input at all. * Warn if Bluesky password isn't app-password-esque App passwords have a pretty regular format, so we can check for that and warn the user that they enter something else, probably their account password. Since the app password format could conceivably change in the future, we leave it at a warning and don't refuse saving in that case. --- .../websites/bluesky/bluesky.service.ts | 16 +-- ui/package-lock.json | 108 ------------------ ui/package.json | 1 - ui/src/websites/bluesky/BlueskyLogin.tsx | 64 ++++++----- 4 files changed, 43 insertions(+), 146 deletions(-) diff --git a/electron-app/src/server/websites/bluesky/bluesky.service.ts b/electron-app/src/server/websites/bluesky/bluesky.service.ts index fa152d35..b8d7ee08 100644 --- a/electron-app/src/server/websites/bluesky/bluesky.service.ts +++ b/electron-app/src/server/websites/bluesky/bluesky.service.ts @@ -37,7 +37,6 @@ import FormData from 'form-data'; // HACK: The atproto library contains some kind of invalid typescript // declaration in @atproto/api, so we can't include directly from it. Rummaging // around in the dist files directly works though. -// This hack is also present in BlueskyLogin.tsx. import { AtUri } from '@atproto/syntax'; import { BlobRef } from '@atproto/lexicon'; import { BskyAgent } from '@atproto/api/dist/bsky-agent'; @@ -71,7 +70,6 @@ export class Bluesky extends Website { // by letting you specify a fetch handler, but then uses Headers and // FormData unconditionally anyway, with no way to change that behavior. // Patching them into the global namespace is ugly, but it works. - // This hack is also present in BlueskyLogin.tsx. globalThis.FormData = FormData as any; globalThis.Headers = fetch.Headers; globalThis.Request = fetch.Request; @@ -80,18 +78,22 @@ export class Bluesky extends Website { } async checkLoginStatus(data: UserAccountEntity): Promise { - const status: LoginResponse = { loggedIn: false, username: null }; - const agent = this.makeAgent(); + const username = data?.data?.username; + const password = data?.data?.password; + if (!username || !password) { + return { loggedIn: false, username }; + } + const status: LoginResponse = { loggedIn: false, username }; + const agent = this.makeAgent(); await agent .login({ - identifier: data.data.username, - password: data.data.password, + identifier: username, + password, }) .then(res => { if (res.success) { status.loggedIn = true; - status.username = data.data.username; } else { status.loggedIn = false; } diff --git a/ui/package-lock.json b/ui/package-lock.json index 737cc263..37d0b7bd 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -9,7 +9,6 @@ "version": "3.1.49", "license": "BSD-3-Clause", "dependencies": { - "@atproto/api": "^0.13.12", "@tinymce/tinymce-react": "^3.8.4", "@types/jest": "24.0.22", "@types/node": "^16.10.2", @@ -393,63 +392,6 @@ "react": "16.x" } }, - "node_modules/@atproto/api": { - "version": "0.13.12", - "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.13.12.tgz", - "integrity": "sha512-U/qimbjlX0MA4MsR+GDuAnFtmdFuGi7eMQZm51s9gbDUw6y4RARL6gaZ0Ju9fBZpS45sI+ShlUHzIoEiBaRvkg==", - "license": "MIT", - "dependencies": { - "@atproto/common-web": "^0.3.1", - "@atproto/lexicon": "^0.4.2", - "@atproto/syntax": "^0.3.0", - "@atproto/xrpc": "^0.6.3", - "await-lock": "^2.2.2", - "multiformats": "^9.9.0", - "tlds": "^1.234.0", - "zod": "^3.23.8" - } - }, - "node_modules/@atproto/common-web": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.3.1.tgz", - "integrity": "sha512-N7wiTnus5vAr+lT//0y8m/FaHHLJ9LpGuEwkwDAeV3LCiPif4m/FS8x/QOYrx1PdZQwKso95RAPzCGWQBH5j6Q==", - "license": "MIT", - "dependencies": { - "graphemer": "^1.4.0", - "multiformats": "^9.9.0", - "uint8arrays": "3.0.0", - "zod": "^3.23.8" - } - }, - "node_modules/@atproto/lexicon": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.2.tgz", - "integrity": "sha512-CXoOkhcdF3XVUnR2oNgCs2ljWfo/8zUjxL5RIhJW/UNLp/FSl+KpF8Jm5fbk8Y/XXVPGRAsv9OYfxyU/14N/pw==", - "license": "MIT", - "dependencies": { - "@atproto/common-web": "^0.3.1", - "@atproto/syntax": "^0.3.0", - "iso-datestring-validator": "^2.2.2", - "multiformats": "^9.9.0", - "zod": "^3.23.8" - } - }, - "node_modules/@atproto/syntax": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.0.tgz", - "integrity": "sha512-Weq0ZBxffGHDXHl9U7BQc2BFJi/e23AL+k+i5+D9hUq/bzT4yjGsrCejkjq0xt82xXDjmhhvQSZ0LqxyZ5woxA==", - "license": "MIT" - }, - "node_modules/@atproto/xrpc": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.6.3.tgz", - "integrity": "sha512-S3tRvOdA9amPkKLll3rc4vphlDitLrkN5TwWh5Tu/jzk7mnobVVE3akYgICV9XCNHKjWM+IAPxFFI2qi+VW6nQ==", - "license": "MIT", - "dependencies": { - "@atproto/lexicon": "^0.4.2", - "zod": "^3.23.8" - } - }, "node_modules/@babel/code-frame": { "version": "7.22.5", "license": "MIT", @@ -3840,12 +3782,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/await-lock": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", - "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==", - "license": "MIT" - }, "node_modules/aws-sign2": { "version": "0.7.0", "license": "Apache-2.0", @@ -8589,12 +8525,6 @@ "version": "4.2.3", "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "license": "MIT" - }, "node_modules/growly": { "version": "1.3.0", "license": "MIT" @@ -9792,12 +9722,6 @@ "version": "2.0.0", "license": "ISC" }, - "node_modules/iso-datestring-validator": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", - "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==", - "license": "MIT" - }, "node_modules/isobject": { "version": "3.0.1", "license": "MIT", @@ -12931,12 +12855,6 @@ "version": "1.1.0", "license": "MIT" }, - "node_modules/multiformats": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", - "license": "(Apache-2.0 AND MIT)" - }, "node_modules/mutationobserver-shim": { "version": "0.3.7", "license": "MIT" @@ -19454,14 +19372,6 @@ "version": "5.10.7", "license": "LGPL-2.1" }, - "node_modules/tlds": { - "version": "1.248.0", - "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.248.0.tgz", - "integrity": "sha512-noj0KdpWTBhwsKxMOXk0rN9otg4kTgLm4WohERRHbJ9IY+kSDKr3RmjitaQ3JFzny+DyvBOQKlFZhp0G0qNSfg==", - "bin": { - "tlds": "bin.js" - } - }, "node_modules/tmp": { "version": "0.0.33", "license": "MIT", @@ -19728,15 +19638,6 @@ "node": ">=0.10.0" } }, - "node_modules/uint8arrays": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", - "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", - "license": "MIT", - "dependencies": { - "multiformats": "^9.4.2" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "license": "MIT", @@ -21179,15 +21080,6 @@ "node_modules/yeast": { "version": "0.1.2", "license": "MIT" - }, - "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } } } diff --git a/ui/package.json b/ui/package.json index c4dcfd0d..1f136a72 100644 --- a/ui/package.json +++ b/ui/package.json @@ -6,7 +6,6 @@ "Author": "Michael DiCarlo", "description": "(UI) PostyBirb is an application that helps artists post art and other multimedia to multiple websites more quickly.", "dependencies": { - "@atproto/api": "^0.13.12", "@tinymce/tinymce-react": "^3.8.4", "@types/jest": "24.0.22", "@types/node": "^16.10.2", diff --git a/ui/src/websites/bluesky/BlueskyLogin.tsx b/ui/src/websites/bluesky/BlueskyLogin.tsx index 933495c6..4624fd11 100644 --- a/ui/src/websites/bluesky/BlueskyLogin.tsx +++ b/ui/src/websites/bluesky/BlueskyLogin.tsx @@ -3,13 +3,6 @@ import React from 'react'; import { BlueskyAccountData } from 'postybirb-commons'; import LoginService from '../../services/login.service'; import { LoginDialogProps } from '../interfaces/website.interface'; -import fetch from 'node-fetch'; -import FormData from 'form-data'; -// HACK: The atproto library contains some kind of invalid typescript -// declaration in @atproto/api, so we can't include directly from it. Rummaging -// around in the dist files directly works though. -// This hack is also present in bluesky.website.service.ts. -import { BskyAgent } from '@atproto/api/dist/bsky-agent'; interface State extends BlueskyAccountData { loading: boolean; @@ -31,30 +24,27 @@ export default class BlueskyLogin extends React.Component { - if (res.success) { - LoginService.setAccountData(this.props.account._id, this.state).then(() => { - message.success(`Details confirmed and saved`); + LoginService.setAccountData(this.props.account._id, { + username: this.state.username, + password: this.state.password, + }) + .then(() => { + LoginService.checkLogin(this.props.account._id) + .then(res => { + if (res.data?.loggedIn) { + message.success('Logged in successfully. You can close this page now.'); + } else { + message.error('Login failed.'); + } + }) + .catch(e => { + console.error('checkLogin failed', e); + message.error(`Failed to check login status: ${e}`); }); - } else { - message.error(`Failed to authenticate.`); - } + }) + .catch(e => { + console.error('setAccountData failed', e); + message.error(`Failed to set account data: ${e}`); }); } @@ -109,6 +99,20 @@ export default class BlueskyLogin extends React.Component this.setState({ password: target.value })} /> + {this.state.password && + !/^([a-z0-9]{4}-){3}[a-z0-9]{4}$/.test(this.state.password) && ( + + You need to use an app password, not your account + password! You can generate an app password in the Bluesky settings under the + Advanced section. + + } + /> + )}