mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
chore: relocate backend into apps/api ahead of monorepo merge
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
// 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 };
|
||||
Reference in New Issue
Block a user