Fix avatar/banner proxy
This commit is contained in:
		
							parent
							
								
									da20675ada
								
							
						
					
					
						commit
						c43a2ce7be
					
				
					 13 changed files with 46 additions and 88 deletions
				
			
		|  | @ -155,6 +155,9 @@ id: 'aid' | |||
| # Media Proxy | ||||
| #mediaProxy: https://example.com/proxy | ||||
| 
 | ||||
| # Proxy remote files (default: false) | ||||
| #proxyRemoteFiles: true | ||||
| 
 | ||||
| # Sign to ActivityPub GET request (default: false) | ||||
| #signToActivityPubGet: true | ||||
| 
 | ||||
|  |  | |||
|  | @ -320,8 +320,6 @@ disablingTimelinesInfo: "これらのタイムラインを無効化しても、 | |||
| registration: "登録" | ||||
| enableRegistration: "誰でも新規登録できるようにする" | ||||
| invite: "招待" | ||||
| proxyRemoteFiles: "リモートのファイルをプロキシする" | ||||
| proxyRemoteFilesDescription: "この設定を有効にすると、未保存または保存容量超過で削除されたリモートファイルをローカルでプロキシし、サムネイルも生成するようになります。サーバーのストレージには影響しません、" | ||||
| driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量" | ||||
| driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量" | ||||
| inMb: "メガバイト単位" | ||||
|  |  | |||
							
								
								
									
										21
									
								
								migration/1626509500668-fix-remote-file-proxy.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								migration/1626509500668-fix-remote-file-proxy.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| import {MigrationInterface, QueryRunner} from "typeorm"; | ||||
| 
 | ||||
| export class fixRemoteFileProxy1626509500668 implements MigrationInterface { | ||||
|     name = 'fixRemoteFileProxy1626509500668' | ||||
| 
 | ||||
|     public async up(queryRunner: QueryRunner): Promise<void> { | ||||
|         await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarUrl"`); | ||||
|         await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerUrl"`); | ||||
|         await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarBlurhash"`); | ||||
|         await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerBlurhash"`); | ||||
|         await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyRemoteFiles"`); | ||||
|     } | ||||
| 
 | ||||
|     public async down(queryRunner: QueryRunner): Promise<void> { | ||||
|         await queryRunner.query(`ALTER TABLE "meta" ADD "proxyRemoteFiles" boolean NOT NULL DEFAULT false`); | ||||
|         await queryRunner.query(`ALTER TABLE "user" ADD "bannerBlurhash" character varying(128)`); | ||||
|         await queryRunner.query(`ALTER TABLE "user" ADD "avatarBlurhash" character varying(128)`); | ||||
|         await queryRunner.query(`ALTER TABLE "user" ADD "bannerUrl" character varying(512)`); | ||||
|         await queryRunner.query(`ALTER TABLE "user" ADD "avatarUrl" character varying(512)`); | ||||
|     } | ||||
| } | ||||
|  | @ -6,11 +6,6 @@ | |||
| 			<template #desc>{{ $ts.cacheRemoteFilesDescription }}</template> | ||||
| 		</FormSwitch> | ||||
| 
 | ||||
| 		<FormSwitch v-model:value="proxyRemoteFiles"> | ||||
| 			{{ $ts.proxyRemoteFiles }} | ||||
| 			<template #desc>{{ $ts.proxyRemoteFilesDescription }}</template> | ||||
| 		</FormSwitch> | ||||
| 
 | ||||
| 		<FormInput v-model:value="localDriveCapacityMb" type="number"> | ||||
| 			<span>{{ $ts.driveCapacityPerLocalAccount }}</span> | ||||
| 			<template #suffix>MB</template> | ||||
|  | @ -59,7 +54,6 @@ export default defineComponent({ | |||
| 				icon: 'fas fa-cloud' | ||||
| 			}, | ||||
| 			cacheRemoteFiles: false, | ||||
| 			proxyRemoteFiles: false, | ||||
| 			localDriveCapacityMb: 0, | ||||
| 			remoteDriveCapacityMb: 0, | ||||
| 		} | ||||
|  | @ -73,14 +67,12 @@ export default defineComponent({ | |||
| 		async init() { | ||||
| 			const meta = await os.api('meta', { detail: true }); | ||||
| 			this.cacheRemoteFiles = meta.cacheRemoteFiles; | ||||
| 			this.proxyRemoteFiles = meta.proxyRemoteFiles; | ||||
| 			this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb; | ||||
| 			this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb; | ||||
| 		}, | ||||
| 		save() { | ||||
| 			os.apiWithDialog('admin/update-meta', { | ||||
| 				cacheRemoteFiles: this.cacheRemoteFiles, | ||||
| 				proxyRemoteFiles: this.proxyRemoteFiles, | ||||
| 				localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10), | ||||
| 				remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10), | ||||
| 			}).then(() => { | ||||
|  |  | |||
|  | @ -60,6 +60,7 @@ export type Source = { | |||
| 	}; | ||||
| 
 | ||||
| 	mediaProxy?: string; | ||||
| 	proxyRemoteFiles?: boolean; | ||||
| 
 | ||||
| 	signToActivityPubGet?: boolean; | ||||
| }; | ||||
|  |  | |||
|  | @ -131,11 +131,6 @@ export class Meta { | |||
| 	}) | ||||
| 	public cacheRemoteFiles: boolean; | ||||
| 
 | ||||
| 	@Column('boolean', { | ||||
| 		default: false, | ||||
| 	}) | ||||
| 	public proxyRemoteFiles: boolean; | ||||
| 
 | ||||
| 	@Column({ | ||||
| 		...id(), | ||||
| 		nullable: true, | ||||
|  |  | |||
|  | @ -106,26 +106,6 @@ export class User { | |||
| 	}) | ||||
| 	public tags: string[]; | ||||
| 
 | ||||
| 	@Column('varchar', { | ||||
| 		length: 512, nullable: true, | ||||
| 	}) | ||||
| 	public avatarUrl: string | null; | ||||
| 
 | ||||
| 	@Column('varchar', { | ||||
| 		length: 512, nullable: true, | ||||
| 	}) | ||||
| 	public bannerUrl: string | null; | ||||
| 
 | ||||
| 	@Column('varchar', { | ||||
| 		length: 128, nullable: true, | ||||
| 	}) | ||||
| 	public avatarBlurhash: string | null; | ||||
| 
 | ||||
| 	@Column('varchar', { | ||||
| 		length: 128, nullable: true, | ||||
| 	}) | ||||
| 	public bannerBlurhash: string | null; | ||||
| 
 | ||||
| 	@Column('boolean', { | ||||
| 		default: false, | ||||
| 		comment: 'Whether the User is suspended.' | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ export class DriveFileRepository extends Repository<DriveFile> { | |||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	public getPublicUrl(file: DriveFile, thumbnail = false, meta?: Meta): string | null { | ||||
| 	public getPublicUrl(file: DriveFile, thumbnail = false): string | null { | ||||
| 		// リモートかつメディアプロキシ
 | ||||
| 		if (file.uri != null && file.userHost != null && config.mediaProxy != null) { | ||||
| 			return appendQuery(config.mediaProxy, query({ | ||||
|  | @ -40,7 +40,7 @@ export class DriveFileRepository extends Repository<DriveFile> { | |||
| 		} | ||||
| 
 | ||||
| 		// リモートかつ期限切れはローカルプロキシを試みる
 | ||||
| 		if (file.uri != null && file.isLink && meta && meta.proxyRemoteFiles) { | ||||
| 		if (file.uri != null && file.isLink && config.proxyRemoteFiles) { | ||||
| 			const key = thumbnail ? file.thumbnailAccessKey : file.webpublicAccessKey; | ||||
| 
 | ||||
| 			if (key && !key.match('/')) {	// 古いものはここにオブジェクトストレージキーが入ってるので除外
 | ||||
|  | @ -113,8 +113,6 @@ export class DriveFileRepository extends Repository<DriveFile> { | |||
| 		const file = typeof src === 'object' ? src : await this.findOne(src); | ||||
| 		if (file == null) return null; | ||||
| 
 | ||||
| 		const meta = await fetchMeta(); | ||||
| 
 | ||||
| 		return await awaitAll({ | ||||
| 			id: file.id, | ||||
| 			createdAt: file.createdAt.toISOString(), | ||||
|  | @ -125,8 +123,8 @@ export class DriveFileRepository extends Repository<DriveFile> { | |||
| 			isSensitive: file.isSensitive, | ||||
| 			blurhash: file.blurhash, | ||||
| 			properties: file.properties, | ||||
| 			url: opts.self ? file.url : this.getPublicUrl(file, false, meta), | ||||
| 			thumbnailUrl: this.getPublicUrl(file, true, meta), | ||||
| 			url: opts.self ? file.url : this.getPublicUrl(file, false), | ||||
| 			thumbnailUrl: this.getPublicUrl(file, true), | ||||
| 			comment: file.comment, | ||||
| 			folderId: file.folderId, | ||||
| 			folder: opts.detail && file.folderId ? DriveFolders.pack(file.folderId, { | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import $ from 'cafy'; | ||||
| import { EntityRepository, Repository, In, Not } from 'typeorm'; | ||||
| import { User, ILocalUser, IRemoteUser } from '@/models/entities/user'; | ||||
| import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '../index'; | ||||
| import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index'; | ||||
| import config from '@/config/index'; | ||||
| import { SchemaType } from '@/misc/schema'; | ||||
| import { awaitAll } from '@/prelude/await-all'; | ||||
|  | @ -170,7 +170,18 @@ export class UserRepository extends Repository<User> { | |||
| 			includeSecrets: false | ||||
| 		}, options); | ||||
| 
 | ||||
| 		const user = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		let user: User; | ||||
| 
 | ||||
| 		if (typeof src === 'object') { | ||||
| 			user = src; | ||||
| 			if (src.avatar === undefined && src.avatarId) src.avatar = await DriveFiles.findOne(src.avatarId) || null; | ||||
| 			if (src.banner === undefined && src.bannerId) src.banner = await DriveFiles.findOne(src.bannerId) || null; | ||||
| 		} else { | ||||
| 			user = await this.findOneOrFail(src, { | ||||
| 				relations: ['avatar', 'banner'] | ||||
| 			}); | ||||
| 		} | ||||
| 
 | ||||
| 		const meId = me ? me.id : null; | ||||
| 
 | ||||
| 		const relation = meId && (meId !== user.id) && opts.detail ? await this.getRelation(meId, user.id) : null; | ||||
|  | @ -188,8 +199,8 @@ export class UserRepository extends Repository<User> { | |||
| 			name: user.name, | ||||
| 			username: user.username, | ||||
| 			host: user.host, | ||||
| 			avatarUrl: user.avatarUrl ? user.avatarUrl : config.url + '/avatar/' + user.id, | ||||
| 			avatarBlurhash: user.avatarBlurhash, | ||||
| 			avatarUrl: user.avatar ? DriveFiles.getPublicUrl(user.avatar, true) : config.url + '/avatar/' + user.id, | ||||
| 			avatarBlurhash: user.avatar?.blurhash || null, | ||||
| 			avatarColor: null, // 後方互換性のため
 | ||||
| 			isAdmin: user.isAdmin || falsy, | ||||
| 			isModerator: user.isModerator || falsy, | ||||
|  | @ -212,8 +223,8 @@ export class UserRepository extends Repository<User> { | |||
| 				createdAt: user.createdAt.toISOString(), | ||||
| 				updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, | ||||
| 				lastFetchedAt: user.lastFetchedAt?.toISOString(), | ||||
| 				bannerUrl: user.bannerUrl, | ||||
| 				bannerBlurhash: user.bannerBlurhash, | ||||
| 				bannerUrl: user.banner ? DriveFiles.getPublicUrl(user.banner, false) : null, | ||||
| 				bannerBlurhash: user.banner?.blurhash || null, | ||||
| 				bannerColor: null, // 後方互換性のため
 | ||||
| 				isLocked: user.isLocked, | ||||
| 				isModerator: user.isModerator || falsy, | ||||
|  |  | |||
|  | @ -231,26 +231,14 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us | |||
| 
 | ||||
| 	const avatarId = avatar ? avatar.id : null; | ||||
| 	const bannerId = banner ? banner.id : null; | ||||
| 	const avatarUrl = avatar ? DriveFiles.getPublicUrl(avatar, true) : null; | ||||
| 	const bannerUrl = banner ? DriveFiles.getPublicUrl(banner) : null; | ||||
| 	const avatarBlurhash = avatar ? avatar.blurhash : null; | ||||
| 	const bannerBlurhash = banner ? banner.blurhash : null; | ||||
| 
 | ||||
| 	await Users.update(user!.id, { | ||||
| 		avatarId, | ||||
| 		bannerId, | ||||
| 		avatarUrl, | ||||
| 		bannerUrl, | ||||
| 		avatarBlurhash, | ||||
| 		bannerBlurhash | ||||
| 	}); | ||||
| 
 | ||||
| 	user!.avatarId = avatarId; | ||||
| 	user!.bannerId = bannerId; | ||||
| 	user!.avatarUrl = avatarUrl; | ||||
| 	user!.bannerUrl = bannerUrl; | ||||
| 	user!.avatarBlurhash = avatarBlurhash; | ||||
| 	user!.bannerBlurhash = bannerBlurhash; | ||||
| 	//#endregion
 | ||||
| 
 | ||||
| 	//#region カスタム絵文字取得
 | ||||
|  | @ -343,14 +331,10 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint | |||
| 
 | ||||
| 	if (avatar) { | ||||
| 		updates.avatarId = avatar.id; | ||||
| 		updates.avatarUrl = DriveFiles.getPublicUrl(avatar, true); | ||||
| 		updates.avatarBlurhash = avatar.blurhash; | ||||
| 	} | ||||
| 
 | ||||
| 	if (banner) { | ||||
| 		updates.bannerId = banner.id; | ||||
| 		updates.bannerUrl = DriveFiles.getPublicUrl(banner); | ||||
| 		updates.bannerBlurhash = banner.blurhash; | ||||
| 	} | ||||
| 
 | ||||
| 	// Update user
 | ||||
|  |  | |||
|  | @ -89,10 +89,6 @@ export const meta = { | |||
| 			validator: $.optional.bool, | ||||
| 		}, | ||||
| 
 | ||||
| 		proxyRemoteFiles: { | ||||
| 			validator: $.optional.bool, | ||||
| 		}, | ||||
| 
 | ||||
| 		enableHcaptcha: { | ||||
| 			validator: $.optional.bool, | ||||
| 		}, | ||||
|  | @ -370,10 +366,6 @@ export default define(meta, async (ps, me) => { | |||
| 		set.cacheRemoteFiles = ps.cacheRemoteFiles; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ps.proxyRemoteFiles !== undefined) { | ||||
| 		set.proxyRemoteFiles = ps.proxyRemoteFiles; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ps.enableHcaptcha !== undefined) { | ||||
| 		set.enableHcaptcha = ps.enableHcaptcha; | ||||
| 	} | ||||
|  |  | |||
|  | @ -195,12 +195,6 @@ export default define(meta, async (ps, _user, token) => { | |||
| 
 | ||||
| 		if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar); | ||||
| 		if (!avatar.type.startsWith('image/')) throw new ApiError(meta.errors.avatarNotAnImage); | ||||
| 
 | ||||
| 		updates.avatarUrl = DriveFiles.getPublicUrl(avatar, true); | ||||
| 
 | ||||
| 		if (avatar.blurhash) { | ||||
| 			updates.avatarBlurhash = avatar.blurhash; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (ps.bannerId) { | ||||
|  | @ -208,12 +202,6 @@ export default define(meta, async (ps, _user, token) => { | |||
| 
 | ||||
| 		if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner); | ||||
| 		if (!banner.type.startsWith('image/')) throw new ApiError(meta.errors.bannerNotAnImage); | ||||
| 
 | ||||
| 		updates.bannerUrl = DriveFiles.getPublicUrl(banner, false); | ||||
| 
 | ||||
| 		if (banner.blurhash) { | ||||
| 			updates.bannerBlurhash = banner.blurhash; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (ps.pinnedPageId) { | ||||
|  |  | |||
|  | @ -100,10 +100,6 @@ export const meta = { | |||
| 				type: 'boolean' as const, | ||||
| 				optional: false as const, nullable: false as const | ||||
| 			}, | ||||
| 			proxyRemoteFiles: { | ||||
| 				type: 'boolean' as const, | ||||
| 				optional: false as const, nullable: false as const | ||||
| 			}, | ||||
| 			enableHcaptcha: { | ||||
| 				type: 'boolean' as const, | ||||
| 				optional: false as const, nullable: false as const | ||||
|  | @ -522,7 +518,6 @@ export default define(meta, async (ps, me) => { | |||
| 			pinnedPages: instance.pinnedPages, | ||||
| 			pinnedClipId: instance.pinnedClipId, | ||||
| 			cacheRemoteFiles: instance.cacheRemoteFiles, | ||||
| 			proxyRemoteFiles: instance.proxyRemoteFiles, | ||||
| 			requireSetup: (await Users.count({ | ||||
| 				host: null, | ||||
| 			})) === 0, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue