mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
56 lines
2.1 KiB
JavaScript
56 lines
2.1 KiB
JavaScript
// utils/resolveAvatar.util.js
|
|
//
|
|
// Resolves a stored avatar into a browser-usable reference at read time.
|
|
//
|
|
// personal_info.avatar is never handed to the browser as a raw S3 URL —
|
|
// same protection as every other media type in this app (see
|
|
// controllers/client/media.controller.js): the browser only ever gets a
|
|
// short-lived opaque stream_token, proxied through
|
|
// GET /client/media/stream/:token, which mints the real presigned URL
|
|
// server-side and pipes the bytes back. The real bucket/key/signature never
|
|
// reach the DOM.
|
|
//
|
|
// - S3-stored avatars (avatar.uuid present) → sign a fresh media JWT from
|
|
// the stored key on every read (never persist a token/URL on the row).
|
|
// - Google-picture avatars (reg_type: 'google', no uuid — see
|
|
// auth.controller.js googleCallback) are an external CDN URL and pass
|
|
// through unchanged as file_url; there's nothing of ours to sign or hide.
|
|
//
|
|
const { signMediaToken } = require('../services/mediaToken.service');
|
|
|
|
async function resolveAvatarUrl(avatar) {
|
|
if (!avatar) return avatar ?? null;
|
|
|
|
if (!avatar.uuid) {
|
|
// External URL (e.g. Google) — nothing to sign, just normalize the field
|
|
// name to match the { stream_token?, file_url? } shape resolveAssetSrc()
|
|
// already expects for every other media payload.
|
|
return { ...avatar, url: undefined, file_url: avatar.url };
|
|
}
|
|
|
|
const token = signMediaToken({
|
|
storage_key: avatar.uuid,
|
|
file_type: 'image',
|
|
mime_type: avatar.mime_type,
|
|
});
|
|
|
|
return { ...avatar, url: undefined, file_url: undefined, stream_token: token };
|
|
}
|
|
|
|
// Mutates-and-returns a shallow copy of a user (plain object or Sequelize
|
|
// instance) with personal_info.avatar resolved. Safe to call on a user with
|
|
// no avatar at all.
|
|
async function resolveUserAvatar(user) {
|
|
if (!user) return user;
|
|
const u = user.toJSON ? user.toJSON() : { ...user };
|
|
if (!u.personal_info?.avatar) return u;
|
|
|
|
u.personal_info = {
|
|
...u.personal_info,
|
|
avatar: await resolveAvatarUrl(u.personal_info.avatar),
|
|
};
|
|
return u;
|
|
}
|
|
|
|
module.exports = { resolveAvatarUrl, resolveUserAvatar };
|