do not use media proxy if emoji is local
Some checks failed
Lint / lint (frontend-embed) (push) Blocked by required conditions
Lint / lint (frontend-shared) (push) Blocked by required conditions
Lint / lint (misskey-bubble-game) (push) Blocked by required conditions
Lint / lint (misskey-js) (push) Blocked by required conditions
Lint / lint (misskey-reversi) (push) Blocked by required conditions
Lint / lint (sw) (push) Blocked by required conditions
Lint / typecheck (backend) (push) Blocked by required conditions
Lint / typecheck (misskey-js) (push) Blocked by required conditions
Lint / typecheck (sw) (push) Blocked by required conditions
Test (backend) / unit (22.11.0) (push) Failing after 1m14s
Lint / pnpm_install (push) Successful in 1m31s
Publish Docker image / Build (push) Failing after 1m49s
Test (production install and build) / production (22.11.0) (push) Failing after 52s
Lint / lint (frontend) (push) Has been cancelled
Lint / lint (backend) (push) Has been cancelled
Test (backend) / e2e (22.11.0) (push) Has been cancelled
Some checks failed
Lint / lint (frontend-embed) (push) Blocked by required conditions
Lint / lint (frontend-shared) (push) Blocked by required conditions
Lint / lint (misskey-bubble-game) (push) Blocked by required conditions
Lint / lint (misskey-js) (push) Blocked by required conditions
Lint / lint (misskey-reversi) (push) Blocked by required conditions
Lint / lint (sw) (push) Blocked by required conditions
Lint / typecheck (backend) (push) Blocked by required conditions
Lint / typecheck (misskey-js) (push) Blocked by required conditions
Lint / typecheck (sw) (push) Blocked by required conditions
Test (backend) / unit (22.11.0) (push) Failing after 1m14s
Lint / pnpm_install (push) Successful in 1m31s
Publish Docker image / Build (push) Failing after 1m49s
Test (production install and build) / production (22.11.0) (push) Failing after 52s
Lint / lint (frontend) (push) Has been cancelled
Lint / lint (backend) (push) Has been cancelled
Test (backend) / e2e (22.11.0) (push) Has been cancelled
Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
This commit is contained in:
parent
95d3fb08f4
commit
07ff53c603
3 changed files with 83 additions and 7 deletions
|
@ -11,15 +11,36 @@ import type { } from '@/models/Blocking.js';
|
|||
import type { MiEmoji } from '@/models/Emoji.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { In } from 'typeorm';
|
||||
import type { Config } from '@/config.js';
|
||||
|
||||
@Injectable()
|
||||
export class EmojiEntityService {
|
||||
constructor(
|
||||
@Inject(DI.emojisRepository)
|
||||
private emojisRepository: EmojisRepository,
|
||||
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
) {
|
||||
}
|
||||
|
||||
private stripProxyIfOrigin(url: string): string {
|
||||
try {
|
||||
const u = new URL(url);
|
||||
if (u.origin === new URL(this.config.url).origin) {
|
||||
return u.searchParams.get('url') ?? url;
|
||||
}
|
||||
if (u.origin === new URL(this.config.mediaProxy).origin) {
|
||||
return u.searchParams.get('url') ?? url;
|
||||
}
|
||||
} catch (e) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
@bindThis
|
||||
public packSimpleNoQuery(
|
||||
emoji: MiEmoji,
|
||||
|
@ -29,7 +50,7 @@ export class EmojiEntityService {
|
|||
name: emoji.name,
|
||||
category: emoji.category,
|
||||
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
|
||||
url: emoji.publicUrl || emoji.originalUrl,
|
||||
url: this.stripProxyIfOrigin(emoji.publicUrl || emoji.originalUrl),
|
||||
localOnly: emoji.localOnly ? true : undefined,
|
||||
isSensitive: emoji.isSensitive ? true : undefined,
|
||||
roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length > 0 ? emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : undefined,
|
||||
|
@ -72,7 +93,7 @@ export class EmojiEntityService {
|
|||
category: emoji.category,
|
||||
host: emoji.host,
|
||||
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
|
||||
url: emoji.publicUrl || emoji.originalUrl,
|
||||
url: this.stripProxyIfOrigin(emoji.publicUrl || emoji.originalUrl),
|
||||
license: emoji.license,
|
||||
isSensitive: emoji.isSensitive,
|
||||
localOnly: emoji.localOnly,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne, ViewEntity } from 'typeorm';
|
||||
import { id } from './util/id.js';
|
||||
import { MiUser } from './User.js';
|
||||
|
||||
|
@ -98,3 +98,34 @@ export class MiFollowing {
|
|||
public followeeSharedInbox: string | null;
|
||||
//#endregion
|
||||
}
|
||||
|
||||
|
||||
@ViewEntity({
|
||||
materialized: true,
|
||||
expression: db => {
|
||||
const items = db.createQueryBuilder()
|
||||
.subQuery()
|
||||
.from(MiFollowing, 'f')
|
||||
.innerJoin(MiUser, 'u', 'f.followerId = u.id')
|
||||
.where({
|
||||
'u.isSuspended': false,
|
||||
'u.isDeleted': false,
|
||||
})
|
||||
.select([
|
||||
'f.followerId',
|
||||
'f.followeeId',
|
||||
])
|
||||
|
||||
return db.createQueryBuilder()
|
||||
.from(items, 'f')
|
||||
.
|
||||
|
||||
}
|
||||
})
|
||||
export class MiFollowingView {
|
||||
public userId: string;
|
||||
|
||||
public followees: MiFollowing[];
|
||||
|
||||
public followeesCount: number;
|
||||
}
|
|
@ -33,7 +33,6 @@ import { OpenApiServerService } from './api/openapi/OpenApiServerService.js';
|
|||
import { OAuth2ProviderService } from './oauth/OAuth2ProviderService.js';
|
||||
import { makeHstsHook } from './hsts.js';
|
||||
import { generateCSP } from './csp.js';
|
||||
import * as prom from 'prom-client';
|
||||
import { sanitizeRequestURI } from '@/misc/log-sanitization.js';
|
||||
import { metricCounter, metricGauge, metricHistogram, MetricsService } from './api/MetricsService.js';
|
||||
|
||||
|
@ -110,6 +109,11 @@ const mLastSuccessfulRequest = metricGauge({
|
|||
labelNames: [],
|
||||
});
|
||||
|
||||
// This function is used to determine if a path is safe to redirect to.
|
||||
function redirectSafePath(path: string): boolean {
|
||||
return ['/files/', '/identicon/', '/proxy/', '/static-assets/', '/vite/', '/embed_vite/'].some(prefix => path.startsWith(prefix));
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ServerService implements OnApplicationShutdown {
|
||||
private logger: Logger;
|
||||
|
@ -348,7 +352,7 @@ export class ServerService implements OnApplicationShutdown {
|
|||
name: name,
|
||||
});
|
||||
|
||||
reply.header('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\'');
|
||||
reply.header('Content-Security-Policy', 'default-src \'none\'');
|
||||
|
||||
if (emoji == null) {
|
||||
if ('fallback' in request.query) {
|
||||
|
@ -359,16 +363,26 @@ export class ServerService implements OnApplicationShutdown {
|
|||
}
|
||||
}
|
||||
|
||||
const dbUrl = emoji?.publicUrl || emoji?.originalUrl;
|
||||
const dbUrlParsed = new URL(dbUrl);
|
||||
const instanceUrl = new URL(this.config.url);
|
||||
if (dbUrlParsed.origin === instanceUrl.origin) {
|
||||
if (!redirectSafePath(dbUrlParsed.pathname)) {
|
||||
return await reply.status(508);
|
||||
}
|
||||
return await reply.redirect(dbUrl, 301);
|
||||
}
|
||||
|
||||
let url: URL;
|
||||
if ('badge' in request.query) {
|
||||
url = new URL(`${this.config.mediaProxy}/emoji.png`);
|
||||
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
|
||||
url.searchParams.set('url', emoji.publicUrl || emoji.originalUrl);
|
||||
url.searchParams.set('url', dbUrl);
|
||||
url.searchParams.set('badge', '1');
|
||||
} else {
|
||||
url = new URL(`${this.config.mediaProxy}/emoji.webp`);
|
||||
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
|
||||
url.searchParams.set('url', emoji.publicUrl || emoji.originalUrl);
|
||||
url.searchParams.set('url', dbUrl);
|
||||
url.searchParams.set('emoji', '1');
|
||||
if ('static' in request.query) url.searchParams.set('static', '1');
|
||||
}
|
||||
|
@ -392,6 +406,16 @@ export class ServerService implements OnApplicationShutdown {
|
|||
reply.header('Cache-Control', 'public, max-age=86400');
|
||||
|
||||
if (user) {
|
||||
const dbUrl = user?.avatarUrl ?? this.userEntityService.getIdenticonUrl(user);
|
||||
const dbUrlParsed = new URL(dbUrl);
|
||||
const instanceUrl = new URL(this.config.url);
|
||||
if (dbUrlParsed.origin === instanceUrl.origin) {
|
||||
if (!redirectSafePath(dbUrlParsed.pathname)) {
|
||||
return await reply.status(508);
|
||||
}
|
||||
return await reply.redirect(dbUrl, 301);
|
||||
}
|
||||
|
||||
reply.redirect(user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user));
|
||||
} else {
|
||||
reply.redirect('/static-assets/user-unknown.png');
|
||||
|
|
Loading…
Reference in a new issue