fix(files): аватары и баннеры доступны авторизованным пользователям
Аватар нельзя было показать в списке друзей: файл без комнаты был доступен только загрузившему. Добавлено назначение файла (`files.purpose`: attachment | avatar | banner, миграция 00006): аватары и баннеры отдаются любому авторизованному пользователю, вложения по-прежнему проверяются по правам комнаты, а непривязанные загрузки остаются приватными.
This commit is contained in:
@@ -130,6 +130,7 @@ func (s *Server) handleAvatarUpload(w http.ResponseWriter, r *http.Request) {
|
||||
UploaderID: ¤tUser.ID,
|
||||
Filename: sanitizeFilename(header.Filename),
|
||||
ContentType: contentType,
|
||||
Purpose: "avatar",
|
||||
}, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
writeHumaAPIError(w, err)
|
||||
@@ -295,6 +296,11 @@ func (s *Server) requireFileAccess(ctx context.Context, rawFileID string, user *
|
||||
if err != nil {
|
||||
return nil, humaError(err)
|
||||
}
|
||||
// Аватары и баннеры видны всем авторизованным: они показываются в списках
|
||||
// участников и друзей (AGENT.md 7.2).
|
||||
if file.Purpose == "avatar" || file.Purpose == "banner" {
|
||||
return file, nil
|
||||
}
|
||||
if file.ChannelID != nil {
|
||||
if _, _, _, err := s.requireChannelPermission(ctx, formatSnowflake(*file.ChannelID), user, permissions.ViewChannel); err != nil {
|
||||
return nil, err
|
||||
@@ -355,6 +361,7 @@ func (s *Server) saveUpload(ctx context.Context, file store.File, content io.Rea
|
||||
SizeBytes: written,
|
||||
StoragePath: path,
|
||||
SHA256: hex.EncodeToString(hasher.Sum(nil)),
|
||||
Purpose: file.Purpose,
|
||||
})
|
||||
if err != nil {
|
||||
_ = os.Remove(path)
|
||||
|
||||
@@ -254,6 +254,25 @@ func TestTimezoneAndAvatarUpdate(t *testing.T) {
|
||||
t.Fatalf("avatar_file_id = %q, want %q", profile.User.AvatarFileID, fileID)
|
||||
}
|
||||
|
||||
// Аватар виден другому авторизованному пользователю (он показывается в
|
||||
// списках друзей и участников), но не анонимному.
|
||||
otherCookie := registerAndLogin(t, srv, "tz_other", "tz-other@example.com")
|
||||
_ = otherCookie
|
||||
downloadReq, err := http.NewRequestWithContext(t.Context(), http.MethodGet,
|
||||
httpServer.URL+"/files/"+fileID, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("new request: %v", err)
|
||||
}
|
||||
downloadReq.AddCookie(otherCookie)
|
||||
downloadResp, err := httpServer.Client().Do(downloadReq)
|
||||
if err != nil {
|
||||
t.Fatalf("avatar download: %v", err)
|
||||
}
|
||||
_ = downloadResp.Body.Close()
|
||||
if downloadResp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("другой пользователь не видит аватар: %d", downloadResp.StatusCode)
|
||||
}
|
||||
|
||||
removed := doJSON(t, srv, http.MethodDelete, "/api/v1/users/@me/avatar", "", cookie)
|
||||
if removed.Code != http.StatusOK {
|
||||
t.Fatalf("delete avatar = %d, body = %s", removed.Code, removed.Body.String())
|
||||
|
||||
Reference in New Issue
Block a user