Files
grendervill a48b865bc9 refactor: убрать вход через внешние провайдеры (OAuth) полностью
Решение владельца 27.09.2026 (D-084): сервис ставится на сервер конкретного
человека, и ему всё равно нужен свой OAuth у провайдера — поддержка общего
входа только создаёт трение (регистрация приложений, redirect URI, модерация,
чужие ключи в конфиге). Способы входа остаются: пароль + 2FA и ключи доступа
(WebAuthn).

Удалено:
- сервер: internal/auth/oauth.go, internal/server/oauth.go, internal/store/oauth.go
  и их тесты; поля и методы конфига OAuth*; oauthLimiter и регистрация ручек;
  отображение ошибок oauth.*; features.oauth_enabled/oauth_providers в /meta;
- клиент: web/src/api/oauth.ts, раздел «Вход через внешние сервисы», кнопки
  провайдеров на странице входа, ключи i18n (ru/en), тесты и фикстуры;
- установщик: переменные OAUTH_* из .env, .env.example и шаблона (хелпер
  чтения существующих значений переименован в existing_value — он остался нужен
  для VAPID_SUBJECT);
- зависимость golang.org/x/oauth2 (go mod tidy).

Схема: миграция 00027 удаляет таблицу oauth_accounts (00019 не переписываем —
она применена на стендах). Откат миграции возвращает структуру; тест
TestOAuthRemovalMigration проверяет накат, откат и повторный накат.

AGENT.md (локальный) помечает пункты про OAuth как отменённые.
2026-09-27 18:27:33 +03:00

67 lines
1.8 KiB
Go

package meta
import (
"encoding/json"
"testing"
"glchat/internal/config"
)
func TestNewBuildsMetaPayload(t *testing.T) {
cfg := config.Config{
Domain: "gl.mhspx.su",
FilesDomain: "files.gl.mhspx.su",
InstanceName: "glchat",
Version: "v0.1.0",
Commit: "abc1234",
BuildDate: "2026-09-19T00:00:00Z",
MaxUploadSize: 26214400,
TLSEnabled: true,
}
resp := New(cfg)
if resp.APIVersion != APIVersion {
t.Errorf("APIVersion = %q, want %q", resp.APIVersion, APIVersion)
}
if resp.BaseURL != "https://gl.mhspx.su" {
t.Errorf("BaseURL = %q", resp.BaseURL)
}
if resp.FilesURL != "https://files.gl.mhspx.su" {
t.Errorf("FilesURL = %q", resp.FilesURL)
}
if resp.GatewayURL != "wss://gl.mhspx.su/gateway" {
t.Errorf("GatewayURL = %q", resp.GatewayURL)
}
if resp.RTCPath != "/rtc" {
t.Errorf("RTCPath = %q", resp.RTCPath)
}
if resp.Version != "v0.1.0" || resp.Commit != "abc1234" {
t.Errorf("version metadata lost: %+v", resp)
}
}
func TestJSONUsesSnakeCaseKeys(t *testing.T) {
raw, err := json.Marshal(New(config.Config{Domain: "example.com", FilesDomain: "files.example.com"}))
if err != nil {
t.Fatalf("marshal meta: %v", err)
}
var decoded map[string]any
if err := json.Unmarshal(raw, &decoded); err != nil {
t.Fatalf("unmarshal meta: %v", err)
}
for _, key := range []string{"api_version", "base_url", "files_url", "gateway_url", "max_upload_size", "features"} {
if _, ok := decoded[key]; !ok {
t.Errorf("meta payload is missing key %q: %s", key, raw)
}
}
features, ok := decoded["features"].(map[string]any)
if !ok {
t.Fatalf("features is not an object: %s", raw)
}
for _, key := range []string{"registration_enabled", "anti_bot_enabled", "voice_enabled", "web_push_enabled", "passkeys_enabled"} {
if _, ok := features[key]; !ok {
t.Errorf("features is missing key %q", key)
}
}
}