mirror of
https://activitypub.software/TransFem-org/Sharkey
synced 2024-09-29 19:34:30 +00:00
Compare commits
21 commits
2e0dddfc07
...
ea3c0e0bea
Author | SHA1 | Date | |
---|---|---|---|
ea3c0e0bea | |||
c224ed031f | |||
8eb8d72889 | |||
674fd13807 | |||
0672ed921e | |||
69efba9366 | |||
c94f6994dd | |||
30c1c7c24d | |||
7c157408af | |||
ceaec33249 | |||
e4cbd58821 | |||
5b282924ea | |||
b667a68bd4 | |||
6ea48be84a | |||
8a982c61c0 | |||
3f6beb97d2 | |||
7439230401 | |||
e9e51fdc01 | |||
62a81bed9b | |||
2e18359dad | |||
b7815df134 |
|
@ -120,9 +120,9 @@
|
|||
"file-type": "19.3.0",
|
||||
"fluent-ffmpeg": "2.1.3",
|
||||
"form-data": "4.0.0",
|
||||
"glob": "10.3.10",
|
||||
"glob": "11.0.0",
|
||||
"got": "14.4.2",
|
||||
"happy-dom": "15.6.1",
|
||||
"happy-dom": "15.7.4",
|
||||
"hpagent": "1.2.0",
|
||||
"htmlescape": "1.1.1",
|
||||
"http-link-header": "1.1.3",
|
||||
|
|
|
@ -245,7 +245,7 @@ export class MfmService {
|
|||
return null;
|
||||
}
|
||||
|
||||
const { window } = new Window();
|
||||
const { happyDOM, window } = new Window();
|
||||
|
||||
const doc = window.document;
|
||||
|
||||
|
@ -463,7 +463,11 @@ export class MfmService {
|
|||
|
||||
appendChildren(nodes, body);
|
||||
|
||||
return new XMLSerializer().serializeToString(body);
|
||||
const serialized = new XMLSerializer().serializeToString(body);
|
||||
|
||||
happyDOM.close().catch(e => {});
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
// the toMastoApiHtml function was taken from Iceshrimp and written by zotan and modified by marie to work with the current MK version
|
||||
|
@ -474,7 +478,7 @@ export class MfmService {
|
|||
return null;
|
||||
}
|
||||
|
||||
const { window } = new Window();
|
||||
const { happyDOM, window } = new Window();
|
||||
|
||||
const doc = window.document;
|
||||
|
||||
|
@ -681,6 +685,8 @@ export class MfmService {
|
|||
result = result.replace(/^<p>/, '').replace(/<\/p>$/, '');
|
||||
}
|
||||
|
||||
happyDOM.close().catch(e => {});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,7 +207,11 @@ export class ApRequestService {
|
|||
//#region リクエスト先がhtmlかつactivity+jsonへのalternate linkタグがあるとき
|
||||
const contentType = res.headers.get('content-type');
|
||||
|
||||
if ((contentType ?? '').split(';')[0].trimEnd().toLowerCase() === 'text/html' && _followAlternate === true) {
|
||||
if (
|
||||
res.ok
|
||||
&& (contentType ?? '').split(';')[0].trimEnd().toLowerCase() === 'text/html'
|
||||
&& _followAlternate === true
|
||||
) {
|
||||
const html = await res.text();
|
||||
const window = new Window({
|
||||
settings: {
|
||||
|
@ -242,6 +246,8 @@ export class ApRequestService {
|
|||
}
|
||||
} catch (e) {
|
||||
// something went wrong parsing the HTML, ignore the whole thing
|
||||
} finally {
|
||||
await window.happyDOM.close();
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
|
|
@ -64,15 +64,6 @@ export class ApiCallService implements OnApplicationShutdown {
|
|||
let statusCode = err.httpStatusCode;
|
||||
if (err.httpStatusCode === 401) {
|
||||
reply.header('WWW-Authenticate', 'Bearer realm="Misskey"');
|
||||
} else if (err.kind === 'client') {
|
||||
reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="invalid_request", error_description="${err.message}"`);
|
||||
statusCode = statusCode ?? 400;
|
||||
} else if (err.kind === 'permission') {
|
||||
// (ROLE_PERMISSION_DENIEDは関係ない)
|
||||
if (err.code === 'PERMISSION_DENIED') {
|
||||
reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="insufficient_scope", error_description="${err.message}"`);
|
||||
}
|
||||
statusCode = statusCode ?? 403;
|
||||
} else if (err.code === 'RATE_LIMIT_EXCEEDED') {
|
||||
const info: unknown = err.info;
|
||||
const unixEpochInSeconds = Date.now();
|
||||
|
@ -83,6 +74,15 @@ export class ApiCallService implements OnApplicationShutdown {
|
|||
} else {
|
||||
this.logger.warn(`rate limit information has unexpected type ${typeof(err.info?.reset)}`);
|
||||
}
|
||||
} else if (err.kind === 'client') {
|
||||
reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="invalid_request", error_description="${err.message}"`);
|
||||
statusCode = statusCode ?? 400;
|
||||
} else if (err.kind === 'permission') {
|
||||
// (ROLE_PERMISSION_DENIEDは関係ない)
|
||||
if (err.code === 'PERMISSION_DENIED') {
|
||||
reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="insufficient_scope", error_description="${err.message}"`);
|
||||
}
|
||||
statusCode = statusCode ?? 403;
|
||||
} else if (!statusCode) {
|
||||
statusCode = 500;
|
||||
}
|
||||
|
|
|
@ -32,18 +32,11 @@ export class RateLimiterService {
|
|||
|
||||
@bindThis
|
||||
public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable<string> }, actor: string, factor = 1) {
|
||||
{
|
||||
if (this.disabled) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// those lines with the "wrong" brace style / indentation are
|
||||
// done that way so that the *other* lines stay identical to
|
||||
// Misskey, simplifying merges
|
||||
return new Promise<void>((ok, reject) => {
|
||||
if (this.disabled) ok();
|
||||
|
||||
// Short-term limit
|
||||
// eslint-disable-next-line brace-style
|
||||
const minP = () => { return new Promise<void>((ok, reject) => {
|
||||
const minP = (): void => {
|
||||
const minIntervalLimiter = new Limiter({
|
||||
id: `${actor}:${limitation.key}:min`,
|
||||
duration: limitation.minInterval! * factor,
|
||||
|
@ -62,18 +55,16 @@ export class RateLimiterService {
|
|||
return reject({ code: 'BRIEF_REQUEST_INTERVAL', info });
|
||||
} else {
|
||||
if (hasLongTermLimit) {
|
||||
return maxP().then(ok, reject);
|
||||
return maxP();
|
||||
} else {
|
||||
return ok();
|
||||
}
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line brace-style
|
||||
}); };
|
||||
};
|
||||
|
||||
// Long term limit
|
||||
// eslint-disable-next-line brace-style
|
||||
const maxP = () => { return new Promise<void>((ok, reject) => {
|
||||
const maxP = (): void => {
|
||||
const limiter = new Limiter({
|
||||
id: `${actor}:${limitation.key}`,
|
||||
duration: limitation.duration! * factor,
|
||||
|
@ -94,8 +85,7 @@ export class RateLimiterService {
|
|||
return ok();
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line brace-style
|
||||
}); };
|
||||
};
|
||||
|
||||
const hasShortTermLimit = typeof limitation.minInterval === 'number';
|
||||
|
||||
|
@ -104,12 +94,12 @@ export class RateLimiterService {
|
|||
typeof limitation.max === 'number';
|
||||
|
||||
if (hasShortTermLimit) {
|
||||
return minP();
|
||||
minP();
|
||||
} else if (hasLongTermLimit) {
|
||||
return maxP();
|
||||
maxP();
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
ok();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { DI } from '@/di-symbols.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['meta'],
|
||||
description: 'Get Sharkey GH Sponsors',
|
||||
description: 'Get Sharkey Sponsors',
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: false,
|
||||
|
@ -30,29 +30,28 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
@Inject(DI.redis) private redisClient: Redis.Redis,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
let sponsors;
|
||||
let totalSponsors;
|
||||
const cachedSponsors = await this.redisClient.get('sponsors');
|
||||
|
||||
if (!ps.forceUpdate && cachedSponsors) {
|
||||
sponsors = JSON.parse(cachedSponsors);
|
||||
totalSponsors = JSON.parse(cachedSponsors);
|
||||
} else {
|
||||
AbortSignal.timeout ??= function timeout(ms) {
|
||||
const ctrl = new AbortController();
|
||||
setTimeout(() => ctrl.abort(), ms);
|
||||
return ctrl.signal;
|
||||
};
|
||||
|
||||
try {
|
||||
sponsors = await fetch('https://kaifa.ch/transfem-sponsors.json', { signal: AbortSignal.timeout(2000) })
|
||||
.then((response) => response.json());
|
||||
const backers = await fetch('https://opencollective.com/sharkey/tiers/backer/all.json').then((response) => response.json());
|
||||
const sponsorsOC = await fetch('https://opencollective.com/sharkey/tiers/sponsor/all.json').then((response) => response.json());
|
||||
|
||||
await this.redisClient.set('sponsors', JSON.stringify(sponsors), 'EX', 3600);
|
||||
// Merge both together into one array and make sure it only has Active subscriptions
|
||||
const allSponsors = [...sponsorsOC, ...backers].filter(sponsor => sponsor.isActive === true);
|
||||
|
||||
// Remove possible duplicates
|
||||
totalSponsors = [...new Map(allSponsors.map(v => [v.profile, v])).values()];
|
||||
|
||||
await this.redisClient.set('sponsors', JSON.stringify(totalSponsors), 'EX', 3600);
|
||||
} catch (error) {
|
||||
sponsors = {
|
||||
sponsors: [],
|
||||
};
|
||||
totalSponsors = [];
|
||||
}
|
||||
}
|
||||
return { sponsor_data: sponsors['sponsors'] };
|
||||
return { sponsor_data: totalSponsors };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,9 +170,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
:key="sponsor"
|
||||
style="margin-bottom: 0.5rem;"
|
||||
>
|
||||
<a :href="sponsor.profile" target="_blank" :class="$style.contributor">
|
||||
<img :src="sponsor.avatar" :class="$style.contributorAvatar">
|
||||
<span :class="$style.contributorUsername">{{ sponsor.details.name }}</span>
|
||||
<a :href="sponsor.website || sponsor.profile" target="_blank" :class="$style.contributor">
|
||||
<img :src="sponsor.image || `https://ui-avatars.com/api/?background=0D8ABC&color=fff&name=${sponsor.name}`" :class="$style.contributorAvatar">
|
||||
<span :class="$style.contributorUsername">{{ sponsor.name }}</span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -209,7 +209,7 @@ const easterEggEngine = ref(null);
|
|||
const sponsors = ref([]);
|
||||
const containerEl = shallowRef<HTMLElement>();
|
||||
|
||||
await misskeyApi('sponsors', { forceUpdate: true }).then((res) => sponsors.value.push(res.sponsor_data));
|
||||
await misskeyApi('sponsors', { forceUpdate: false }).then((res) => sponsors.value.push(res.sponsor_data));
|
||||
|
||||
function iconLoaded() {
|
||||
const emojis = defaultStore.state.reactions;
|
||||
|
|
|
@ -251,14 +251,14 @@ importers:
|
|||
specifier: 4.0.0
|
||||
version: 4.0.0
|
||||
glob:
|
||||
specifier: 10.3.10
|
||||
version: 10.3.10
|
||||
specifier: 11.0.0
|
||||
version: 11.0.0
|
||||
got:
|
||||
specifier: 14.4.2
|
||||
version: 14.4.2
|
||||
happy-dom:
|
||||
specifier: 15.6.1
|
||||
version: 15.6.1
|
||||
specifier: 15.7.4
|
||||
version: 15.7.4
|
||||
hpagent:
|
||||
specifier: 1.2.0
|
||||
version: 1.2.0
|
||||
|
@ -7586,11 +7586,6 @@ packages:
|
|||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
hasBin: true
|
||||
|
||||
glob@10.4.2:
|
||||
resolution: {integrity: sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
hasBin: true
|
||||
|
||||
glob@11.0.0:
|
||||
resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
@ -7677,8 +7672,8 @@ packages:
|
|||
happy-dom@10.0.3:
|
||||
resolution: {integrity: sha512-WkCP+Z5fX6U5PY+yHP3ElV5D9PoxRAHRWPFq3pG9rg/6Hjf5ak7dozAgSCywsTRUq2qfa8vV8OQvUy5pRXy8EQ==}
|
||||
|
||||
happy-dom@15.6.1:
|
||||
resolution: {integrity: sha512-dsMHLsJHZYhXeExP47B2siAfKNVxptlwFss3/bq/9sG3iBt0P2WYFBq68JgMR5vB5gsN2Ev0feTTPD/+rosUNQ==}
|
||||
happy-dom@15.7.4:
|
||||
resolution: {integrity: sha512-r1vadDYGMtsHAAsqhDuk4IpPvr6N8MGKy5ntBo7tSdim+pWDxus2PNqOcOt8LuDZ4t3KJHE+gCuzupcx/GKnyQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
hard-rejection@2.1.0:
|
||||
|
@ -7908,6 +7903,7 @@ packages:
|
|||
|
||||
inflight@1.0.6:
|
||||
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
||||
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
|
||||
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
@ -8226,10 +8222,6 @@ packages:
|
|||
resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
jackspeak@3.4.0:
|
||||
resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
jackspeak@4.0.1:
|
||||
resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
@ -9544,10 +9536,6 @@ packages:
|
|||
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
path-scurry@1.11.1:
|
||||
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
|
||||
path-scurry@2.0.0:
|
||||
resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
@ -11134,7 +11122,6 @@ packages:
|
|||
|
||||
ts-case-convert@2.0.2:
|
||||
resolution: {integrity: sha512-vdKfx1VAdpvEBOBv5OpVu5ZFqRg9HdTI4sYt6qqMeICBeNyXvitrarCnFWNDAki51IKwCyx+ZssY46Q9jH5otA==}
|
||||
bundledDependencies: []
|
||||
|
||||
ts-dedent@2.2.0:
|
||||
resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
|
||||
|
@ -14095,7 +14082,7 @@ snapshots:
|
|||
content-disposition: 0.5.4
|
||||
fastify-plugin: 4.5.0
|
||||
fastq: 1.17.1
|
||||
glob: 10.4.2
|
||||
glob: 10.3.10
|
||||
|
||||
'@fastify/view@8.2.0':
|
||||
dependencies:
|
||||
|
@ -20049,15 +20036,6 @@ snapshots:
|
|||
minipass: 7.0.4
|
||||
path-scurry: 1.10.1
|
||||
|
||||
glob@10.4.2:
|
||||
dependencies:
|
||||
foreground-child: 3.1.1
|
||||
jackspeak: 3.4.0
|
||||
minimatch: 9.0.4
|
||||
minipass: 7.1.2
|
||||
package-json-from-dist: 1.0.0
|
||||
path-scurry: 1.11.1
|
||||
|
||||
glob@11.0.0:
|
||||
dependencies:
|
||||
foreground-child: 3.1.1
|
||||
|
@ -20194,7 +20172,7 @@ snapshots:
|
|||
whatwg-encoding: 2.0.0
|
||||
whatwg-mimetype: 3.0.0
|
||||
|
||||
happy-dom@15.6.1:
|
||||
happy-dom@15.7.4:
|
||||
dependencies:
|
||||
entities: 4.5.0
|
||||
webidl-conversions: 7.0.0
|
||||
|
@ -20709,12 +20687,6 @@ snapshots:
|
|||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
jackspeak@3.4.0:
|
||||
dependencies:
|
||||
'@isaacs/cliui': 8.0.2
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
jackspeak@4.0.1:
|
||||
dependencies:
|
||||
'@isaacs/cliui': 8.0.2
|
||||
|
@ -22449,11 +22421,6 @@ snapshots:
|
|||
lru-cache: 10.2.2
|
||||
minipass: 7.0.4
|
||||
|
||||
path-scurry@1.11.1:
|
||||
dependencies:
|
||||
lru-cache: 10.2.2
|
||||
minipass: 7.1.2
|
||||
|
||||
path-scurry@2.0.0:
|
||||
dependencies:
|
||||
lru-cache: 11.0.0
|
||||
|
|
Loading…
Reference in a new issue