Allow revoke access token

- Also means storing client credentials
- A bit of cleaning up for vapid key as it's everywhere now
pull/1176/head
Lim Chee Aun 2025-05-27 16:57:29 +08:00
rodzic 35af0a0e84
commit e7ffccf9d1
6 zmienionych plików z 77 dodań i 17 usunięć

Wyświetl plik

@ -63,7 +63,9 @@ import states, { initStates, statusKey } from './utils/states';
import store from './utils/store'; import store from './utils/store';
import { import {
getAccount, getAccount,
getCredentialApplication,
getCurrentAccount, getCurrentAccount,
getVapidKey,
setCurrentAccountID, setCurrentAccountID,
} from './utils/store-utils'; } from './utils/store-utils';
@ -367,9 +369,12 @@ function App() {
window.location.pathname || '/', window.location.pathname || '/',
); );
const clientID = store.sessionCookie.get('clientID'); const {
const clientSecret = store.sessionCookie.get('clientSecret'); client_id: clientID,
const vapidKey = store.sessionCookie.get('vapidKey'); client_secret: clientSecret,
vapid_key,
} = getCredentialApplication(instanceURL) || {};
const vapidKey = getVapidKey(instanceURL) || vapid_key;
const verifier = store.sessionCookie.get('codeVerifier'); const verifier = store.sessionCookie.get('codeVerifier');
(async () => { (async () => {

Wyświetl plik

@ -14,6 +14,7 @@ import Menu2 from '../components/menu2';
import NameText from '../components/name-text'; import NameText from '../components/name-text';
import RelativeTime from '../components/relative-time'; import RelativeTime from '../components/relative-time';
import { api } from '../utils/api'; import { api } from '../utils/api';
import { revokeAccessToken } from '../utils/auth';
import niceDateTime from '../utils/nice-date-time'; import niceDateTime from '../utils/nice-date-time';
import states from '../utils/states'; import states from '../utils/states';
import store from '../utils/store'; import store from '../utils/store';
@ -185,9 +186,15 @@ function Accounts({ onClose }) {
} }
disabled={!isCurrent} disabled={!isCurrent}
menuItemClassName="danger" menuItemClassName="danger"
onClick={() => { onClick={async () => {
// const yes = confirm('Log out?'); // const yes = confirm('Log out?');
// if (!yes) return; // if (!yes) return;
await revokeAccessToken({
instanceURL: account.instanceURL,
client_id: account.clientId,
client_secret: account.clientSecret,
token: account.accessToken,
});
accounts.splice(i, 1); accounts.splice(i, 1);
store.local.setJSON('accounts', accounts); store.local.setJSON('accounts', accounts);
// location.reload(); // location.reload();

Wyświetl plik

@ -18,6 +18,10 @@ import {
} from '../utils/auth'; } from '../utils/auth';
import { supportsPKCE } from '../utils/oauth-pkce'; import { supportsPKCE } from '../utils/oauth-pkce';
import store from '../utils/store'; import store from '../utils/store';
import {
getCredentialApplication,
storeCredentialApplication,
} from '../utils/store-utils';
import useTitle from '../utils/useTitle'; import useTitle from '../utils/useTitle';
const { PHANPY_DEFAULT_INSTANCE: DEFAULT_INSTANCE } = import.meta.env; const { PHANPY_DEFAULT_INSTANCE: DEFAULT_INSTANCE } = import.meta.env;
@ -87,19 +91,20 @@ function Login() {
setUIState('loading'); setUIState('loading');
try { try {
const { client_id, client_secret, vapid_key } = let credentialApplication = getCredentialApplication(instanceURL);
await registerApplication({ if (!credentialApplication) {
credentialApplication = await registerApplication({
instanceURL, instanceURL,
}); });
storeCredentialApplication(instanceURL, credentialApplication);
}
const { client_id, client_secret } = credentialApplication;
const authPKCE = await supportsPKCE({ instanceURL }); const authPKCE = await supportsPKCE({ instanceURL });
console.log({ authPKCE }); console.log({ authPKCE });
if (authPKCE) { if (authPKCE) {
if (client_id && client_secret) { if (client_id && client_secret) {
store.sessionCookie.set('clientID', client_id);
store.sessionCookie.set('clientSecret', client_secret);
store.sessionCookie.set('vapidKey', vapid_key);
const [url, verifier] = await getPKCEAuthorizationURL({ const [url, verifier] = await getPKCEAuthorizationURL({
instanceURL, instanceURL,
client_id, client_id,
@ -111,10 +116,6 @@ function Login() {
} }
} else { } else {
if (client_id && client_secret) { if (client_id && client_secret) {
store.sessionCookie.set('clientID', client_id);
store.sessionCookie.set('clientSecret', client_secret);
store.sessionCookie.set('vapidKey', vapid_key);
location.href = await getAuthorizationURL({ location.href = await getAuthorizationURL({
instanceURL, instanceURL,
client_id, client_id,

Wyświetl plik

@ -24,7 +24,7 @@ import {
import showToast from '../utils/show-toast'; import showToast from '../utils/show-toast';
import states from '../utils/states'; import states from '../utils/states';
import store from '../utils/store'; import store from '../utils/store';
import { getAPIVersions } from '../utils/store-utils'; import { getAPIVersions, getVapidKey } from '../utils/store-utils';
import supports from '../utils/supports'; import supports from '../utils/supports';
const DEFAULT_TEXT_SIZE = 16; const DEFAULT_TEXT_SIZE = 16;
@ -860,6 +860,9 @@ function Settings({ onClose }) {
</Link> </Link>
</p> </p>
<p>Debugging</p> <p>Debugging</p>
<p>
<b>Vapid key</b>: {getVapidKey()}
</p>
{__BENCH_RESULTS?.size > 0 && ( {__BENCH_RESULTS?.size > 0 && (
<ul> <ul>
{Array.from(__BENCH_RESULTS.entries()).map( {Array.from(__BENCH_RESULTS.entries()).map(

Wyświetl plik

@ -105,3 +105,32 @@ export async function getAccessToken({
console.log({ tokenJSON }); console.log({ tokenJSON });
return tokenJSON; return tokenJSON;
} }
export async function revokeAccessToken({
instanceURL,
client_id,
client_secret,
token,
}) {
try {
const params = new URLSearchParams({
client_id,
client_secret,
token,
});
const revokeResponse = await fetch(`https://${instanceURL}/oauth/revoke`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params.toString(),
keepalive: true,
});
return revokeResponse.ok;
} catch (error) {
console.erro('Error revoking token', error);
return false;
}
}

Wyświetl plik

@ -169,9 +169,11 @@ export function getAPIVersions() {
return instance?.apiVersions || {}; return instance?.apiVersions || {};
} }
export function getVapidKey() { export function getVapidKey(instance) {
// Vapid key has moved from account to instance config // Vapid key has moved from account to instance config
const config = getCurrentInstanceConfiguration(); const config = instance
? getInstanceConfiguration(instance)
: getCurrentInstanceConfiguration();
const vapidKey = config?.vapid?.publicKey || config?.vapid?.public_key; const vapidKey = config?.vapid?.publicKey || config?.vapid?.public_key;
return vapidKey || getCurrentAccount()?.vapidKey; return vapidKey || getCurrentAccount()?.vapidKey;
} }
@ -180,3 +182,16 @@ export function isMediaFirstInstance() {
const instance = getCurrentInstance(); const instance = getCurrentInstance();
return /pixelfed/i.test(instance?.version); return /pixelfed/i.test(instance?.version);
} }
const CREDENTIAL_APPLICATIONS_KEY = 'credentialApplications';
export function storeCredentialApplication(instanceURL, credentialApplication) {
const stored = store.local.getJSON(CREDENTIAL_APPLICATIONS_KEY) || {};
stored[instanceURL] = credentialApplication;
store.local.setJSON(CREDENTIAL_APPLICATIONS_KEY, stored);
}
export function getCredentialApplication(instanceURL) {
const stored = store.local.getJSON(CREDENTIAL_APPLICATIONS_KEY) || {};
return stored[instanceURL] || null;
}