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

Wyświetl plik

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

Wyświetl plik

@ -18,6 +18,10 @@ import {
} from '../utils/auth';
import { supportsPKCE } from '../utils/oauth-pkce';
import store from '../utils/store';
import {
getCredentialApplication,
storeCredentialApplication,
} from '../utils/store-utils';
import useTitle from '../utils/useTitle';
const { PHANPY_DEFAULT_INSTANCE: DEFAULT_INSTANCE } = import.meta.env;
@ -87,19 +91,20 @@ function Login() {
setUIState('loading');
try {
const { client_id, client_secret, vapid_key } =
await registerApplication({
let credentialApplication = getCredentialApplication(instanceURL);
if (!credentialApplication) {
credentialApplication = await registerApplication({
instanceURL,
});
storeCredentialApplication(instanceURL, credentialApplication);
}
const { client_id, client_secret } = credentialApplication;
const authPKCE = await supportsPKCE({ instanceURL });
console.log({ authPKCE });
if (authPKCE) {
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({
instanceURL,
client_id,
@ -111,10 +116,6 @@ function Login() {
}
} else {
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({
instanceURL,
client_id,

Wyświetl plik

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

Wyświetl plik

@ -105,3 +105,32 @@ export async function getAccessToken({
console.log({ 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 || {};
}
export function getVapidKey() {
export function getVapidKey(instance) {
// 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;
return vapidKey || getCurrentAccount()?.vapidKey;
}
@ -180,3 +182,16 @@ export function isMediaFirstInstance() {
const instance = getCurrentInstance();
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;
}