pl-api: allow username+password log in with iceshrimp.net
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@@ -281,6 +281,7 @@ class PlApiClient {
|
|||||||
|
|
||||||
baseURL: string;
|
baseURL: string;
|
||||||
#accessToken?: string;
|
#accessToken?: string;
|
||||||
|
#iceshrimpAccessToken?: string;
|
||||||
#instance: Instance = v.parse(instanceSchema, {});
|
#instance: Instance = v.parse(instanceSchema, {});
|
||||||
public request = request.bind(this) as typeof request;
|
public request = request.bind(this) as typeof request;
|
||||||
public features: Features = getFeatures(this.#instance);
|
public features: Features = getFeatures(this.#instance);
|
||||||
@@ -505,9 +506,49 @@ class PlApiClient {
|
|||||||
* @see {@link https://docs.joinmastodon.org/methods/oauth/#token}
|
* @see {@link https://docs.joinmastodon.org/methods/oauth/#token}
|
||||||
*/
|
*/
|
||||||
getToken: async (params: GetTokenParams) => {
|
getToken: async (params: GetTokenParams) => {
|
||||||
const response = await this.request('/oauth/token', { method: 'POST', body: params });
|
if (this.features.version.software === ICESHRIMP_NET && params.grant_type === 'password') {
|
||||||
|
const loginResponse = (await this.request<{
|
||||||
|
token: string;
|
||||||
|
}>('/api/iceshrimp/auth/login', {
|
||||||
|
method: 'POST',
|
||||||
|
body: {
|
||||||
|
username: params.username,
|
||||||
|
password: params.password,
|
||||||
|
}
|
||||||
|
})).json;
|
||||||
|
this.#iceshrimpAccessToken = loginResponse.token;
|
||||||
|
|
||||||
return v.parse(tokenSchema, { scope: params.scope || '', ...response.json });
|
const mastodonTokenResponse = (await this.request<{
|
||||||
|
id: string;
|
||||||
|
token: string;
|
||||||
|
created_at: string;
|
||||||
|
scopes: Array<string>;
|
||||||
|
}>('/api/iceshrimp/sessions/mastodon', {
|
||||||
|
method: 'POST',
|
||||||
|
body: {
|
||||||
|
appName: params.client_id,
|
||||||
|
scopes: params.scope?.split(' '),
|
||||||
|
flags: {
|
||||||
|
supportsHtmlFormatting: true,
|
||||||
|
autoDetectQuotes: false,
|
||||||
|
isPleroma: true,
|
||||||
|
supportsInlineMedia: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})).json;
|
||||||
|
|
||||||
|
return v.parse(tokenSchema, {
|
||||||
|
access_token: mastodonTokenResponse.token,
|
||||||
|
token_type: 'Bearer',
|
||||||
|
scope: mastodonTokenResponse.scopes.join(' '),
|
||||||
|
created_at: new Date(mastodonTokenResponse.created_at).getTime(),
|
||||||
|
id: mastodonTokenResponse.id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const response = await this.request('/oauth/token', { method: 'POST', body: params });
|
||||||
|
|
||||||
|
return v.parse(tokenSchema, { scope: params.scope || '', ...response.json });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1850,6 +1891,12 @@ class PlApiClient {
|
|||||||
|
|
||||||
return v.parse(v.object({ frontend_name: v.string() }), response.json);
|
return v.parse(v.object({ frontend_name: v.string() }), response.json);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
authorizeIceshrimp: async () => {
|
||||||
|
const response = await this.request<string>('/api/v1/accounts/authorize_iceshrimp', { method: 'POST' });
|
||||||
|
|
||||||
|
return response.json;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
public readonly filtering = {
|
public readonly filtering = {
|
||||||
@@ -5724,6 +5771,12 @@ class PlApiClient {
|
|||||||
this.features = getFeatures(this.#instance);
|
this.features = getFeatures(this.#instance);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#getIceshrimpAccessToken = async () => {
|
||||||
|
if (this.features.version.software === ICESHRIMP_NET) {
|
||||||
|
this.#iceshrimpAccessToken = await this.settings.authorizeIceshrimp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get accessToken(): string | undefined {
|
get accessToken(): string | undefined {
|
||||||
return this.#accessToken;
|
return this.#accessToken;
|
||||||
}
|
}
|
||||||
@@ -5733,6 +5786,12 @@ class PlApiClient {
|
|||||||
|
|
||||||
this.#socket?.close();
|
this.#socket?.close();
|
||||||
this.#accessToken = accessToken;
|
this.#accessToken = accessToken;
|
||||||
|
|
||||||
|
this.#getIceshrimpAccessToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
get iceshrimpAccessToken(): string | undefined {
|
||||||
|
return this.#iceshrimpAccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
get instanceInformation() {
|
get instanceInformation() {
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ class PlApiDirectoryClient {
|
|||||||
|
|
||||||
/** Unused. */
|
/** Unused. */
|
||||||
accessToken: string | undefined = undefined;
|
accessToken: string | undefined = undefined;
|
||||||
|
/** Unused. */
|
||||||
|
iceshrimpAccessToken: string | undefined = undefined;
|
||||||
/**
|
/**
|
||||||
* Server directory URL.
|
* Server directory URL.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ interface GetTokenParams {
|
|||||||
redirect_uri: string;
|
redirect_uri: string;
|
||||||
/** String. List of requested OAuth scopes, separated by spaces (or by pluses, if using query parameters). If `code` was provided, then this must be equal to the `scope` requested from the user. Otherwise, it must be a subset of `scopes` declared during app registration. If not provided, defaults to `read`. */
|
/** String. List of requested OAuth scopes, separated by spaces (or by pluses, if using query parameters). If `code` was provided, then this must be equal to the `scope` requested from the user. Otherwise, it must be a subset of `scopes` declared during app registration. If not provided, defaults to `read`. */
|
||||||
scope?: string;
|
scope?: string;
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ interface RequestBody<Params = Record<string, any>> {
|
|||||||
|
|
||||||
type RequestMeta = Pick<RequestBody, 'idempotencyKey' | 'onUploadProgress' | 'signal'>;
|
type RequestMeta = Pick<RequestBody, 'idempotencyKey' | 'onUploadProgress' | 'signal'>;
|
||||||
|
|
||||||
function request<T = any>(this: Pick<PlApiClient, 'accessToken' | 'baseURL'>, input: URL | RequestInfo, {
|
function request<T = any>(this: Pick<PlApiClient, 'accessToken' | 'iceshrimpAccessToken' | 'baseURL'>, input: URL | RequestInfo, {
|
||||||
body,
|
body,
|
||||||
method = body ? 'POST' : 'GET',
|
method = body ? 'POST' : 'GET',
|
||||||
params,
|
params,
|
||||||
@@ -51,10 +51,12 @@ function request<T = any>(this: Pick<PlApiClient, 'accessToken' | 'baseURL'>, in
|
|||||||
contentType = 'application/json',
|
contentType = 'application/json',
|
||||||
idempotencyKey,
|
idempotencyKey,
|
||||||
}: RequestBody = {}) {
|
}: RequestBody = {}) {
|
||||||
const fullPath = buildFullPath(input.toString(), this.baseURL, params);
|
input = input.toString();
|
||||||
|
const fullPath = buildFullPath(input, this.baseURL, params);
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
|
|
||||||
if (this.accessToken) headers.set('Authorization', `Bearer ${this.accessToken}`);
|
if (input.startsWith('/api/iceshrimp/') && this.iceshrimpAccessToken) headers.set('Authorization', `Bearer ${this.iceshrimpAccessToken}`);
|
||||||
|
else if (this.accessToken) headers.set('Authorization', `Bearer ${this.accessToken}`);
|
||||||
if (contentType !== '' && body) headers.set('Content-Type', contentType);
|
if (contentType !== '' && body) headers.set('Content-Type', contentType);
|
||||||
if (idempotencyKey) headers.set('Idempotency-Key', contentType);
|
if (idempotencyKey) headers.set('Idempotency-Key', contentType);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pl-api",
|
"name": "pl-api",
|
||||||
"version": "1.0.0-rc.61",
|
"version": "1.0.0-rc.62",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"homepage": "https://github.com/mkljczk/pl-fe/tree/develop/packages/pl-api",
|
"homepage": "https://github.com/mkljczk/pl-fe/tree/develop/packages/pl-api",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -104,7 +104,7 @@
|
|||||||
"multiselect-react-dropdown": "^2.0.25",
|
"multiselect-react-dropdown": "^2.0.25",
|
||||||
"mutative": "^1.1.0",
|
"mutative": "^1.1.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"pl-api": "^1.0.0-rc.61",
|
"pl-api": "^1.0.0-rc.62",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ import { getBaseURL } from 'pl-fe/utils/state';
|
|||||||
|
|
||||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||||
|
|
||||||
const obtainOAuthToken = (params: GetTokenParams, baseURL?: string) =>{
|
const obtainOAuthToken = async (params: GetTokenParams, baseURL?: string) =>{
|
||||||
const client = new PlApiClient(baseURL || BuildConfig.BACKEND_URL || '');
|
const client = new PlApiClient(baseURL || BuildConfig.BACKEND_URL || '');
|
||||||
|
await client.instance.getInstance();
|
||||||
|
|
||||||
return client.oauth.getToken(params);
|
return client.oauth.getToken(params);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ const getInstanceScopes = (instance: Instance, admin: boolean = true) => {
|
|||||||
let scopes;
|
let scopes;
|
||||||
|
|
||||||
switch (v.software) {
|
switch (v.software) {
|
||||||
|
case ICESHRIMP_NET:
|
||||||
|
scopes = 'read write follow push iceshrimp';
|
||||||
|
break;
|
||||||
case TOKI:
|
case TOKI:
|
||||||
scopes = 'read write follow push write:bites';
|
scopes = 'read write follow push write:bites';
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -6863,10 +6863,10 @@ pkg-dir@^4.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
find-up "^4.0.0"
|
find-up "^4.0.0"
|
||||||
|
|
||||||
pl-api@^1.0.0-rc.61:
|
pl-api@^1.0.0-rc.62:
|
||||||
version "1.0.0-rc.61"
|
version "1.0.0-rc.62"
|
||||||
resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-1.0.0-rc.61.tgz#0d9969c9691e77109d3c66db02c55a0d866c1429"
|
resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-1.0.0-rc.62.tgz#d838b1cde4b9b4d9ed986d99f503d8f460039088"
|
||||||
integrity sha512-fShtnSPaJ/EUMqExk/eV5nJHG4vfxMgQBS0Qdrqk9PNEVoWAaazkxa6nNoXDAZ0bx+39+JlS0DyOwoet5GkYRg==
|
integrity sha512-X6LN7fS874czsouIwBPx/nw7EGQtscJDixxkpF3fM7tQR8Ficn7dRfJuDgzpv1MLovxqnXC3Sn9TVVWWA+TCdg==
|
||||||
dependencies:
|
dependencies:
|
||||||
blurhash "^2.0.5"
|
blurhash "^2.0.5"
|
||||||
http-link-header "^1.1.3"
|
http-link-header "^1.1.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user