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;
|
||||
#accessToken?: string;
|
||||
#iceshrimpAccessToken?: string;
|
||||
#instance: Instance = v.parse(instanceSchema, {});
|
||||
public request = request.bind(this) as typeof request;
|
||||
public features: Features = getFeatures(this.#instance);
|
||||
@ -505,9 +506,49 @@ class PlApiClient {
|
||||
* @see {@link https://docs.joinmastodon.org/methods/oauth/#token}
|
||||
*/
|
||||
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);
|
||||
},
|
||||
|
||||
authorizeIceshrimp: async () => {
|
||||
const response = await this.request<string>('/api/v1/accounts/authorize_iceshrimp', { method: 'POST' });
|
||||
|
||||
return response.json;
|
||||
},
|
||||
};
|
||||
|
||||
public readonly filtering = {
|
||||
@ -5724,6 +5771,12 @@ class PlApiClient {
|
||||
this.features = getFeatures(this.#instance);
|
||||
};
|
||||
|
||||
#getIceshrimpAccessToken = async () => {
|
||||
if (this.features.version.software === ICESHRIMP_NET) {
|
||||
this.#iceshrimpAccessToken = await this.settings.authorizeIceshrimp();
|
||||
}
|
||||
}
|
||||
|
||||
get accessToken(): string | undefined {
|
||||
return this.#accessToken;
|
||||
}
|
||||
@ -5733,6 +5786,12 @@ class PlApiClient {
|
||||
|
||||
this.#socket?.close();
|
||||
this.#accessToken = accessToken;
|
||||
|
||||
this.#getIceshrimpAccessToken();
|
||||
}
|
||||
|
||||
get iceshrimpAccessToken(): string | undefined {
|
||||
return this.#iceshrimpAccessToken;
|
||||
}
|
||||
|
||||
get instanceInformation() {
|
||||
|
||||
@ -28,6 +28,8 @@ class PlApiDirectoryClient {
|
||||
|
||||
/** Unused. */
|
||||
accessToken: string | undefined = undefined;
|
||||
/** Unused. */
|
||||
iceshrimpAccessToken: string | undefined = undefined;
|
||||
/**
|
||||
* Server directory URL.
|
||||
*/
|
||||
|
||||
@ -32,6 +32,8 @@ interface GetTokenParams {
|
||||
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`. */
|
||||
scope?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -42,7 +42,7 @@ interface RequestBody<Params = Record<string, any>> {
|
||||
|
||||
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,
|
||||
method = body ? 'POST' : 'GET',
|
||||
params,
|
||||
@ -51,10 +51,12 @@ function request<T = any>(this: Pick<PlApiClient, 'accessToken' | 'baseURL'>, in
|
||||
contentType = 'application/json',
|
||||
idempotencyKey,
|
||||
}: RequestBody = {}) {
|
||||
const fullPath = buildFullPath(input.toString(), this.baseURL, params);
|
||||
input = input.toString();
|
||||
const fullPath = buildFullPath(input, this.baseURL, params);
|
||||
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 (idempotencyKey) headers.set('Idempotency-Key', contentType);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user