refactor: simplify auth and subscription links
This commit is contained in:
@@ -1,241 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/peterqiu0516/sub-store/internal/model"
|
||||
"github.com/peterqiu0516/sub-store/internal/util"
|
||||
)
|
||||
|
||||
type GrantRepo struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
func NewGrantRepo(db *sqlx.DB) *GrantRepo {
|
||||
return &GrantRepo{db: db}
|
||||
}
|
||||
|
||||
type grantRow struct {
|
||||
ID string `db:"id"`
|
||||
TokenHash string `db:"token_hash"`
|
||||
ResourceType string `db:"resource_type"`
|
||||
ResourceID string `db:"resource_id"`
|
||||
Target string `db:"target"`
|
||||
ExpiresAt *int64 `db:"expires_at"`
|
||||
Enabled int `db:"enabled"`
|
||||
CreatedAt int64 `db:"created_at"`
|
||||
UpdatedAt int64 `db:"updated_at"`
|
||||
}
|
||||
|
||||
// CreateGrant creates a new download grant, returning the grant record and the plaintext token.
|
||||
func (r *GrantRepo) Create(resourceType, resourceID, target string, expiresAt *int64) (model.DownloadGrantRecord, string, error) {
|
||||
now := time.Now().UnixMilli()
|
||||
id := uuid.New().String()
|
||||
token, err := util.RandomToken()
|
||||
if err != nil {
|
||||
return model.DownloadGrantRecord{}, "", err
|
||||
}
|
||||
tokenHash := util.SHA256Hex(token)
|
||||
|
||||
_, err = r.db.Exec(
|
||||
`INSERT INTO download_grants (id, token_hash, resource_type, resource_id, target, expires_at, enabled, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)`,
|
||||
id, tokenHash, resourceType, resourceID, target, expiresAt, now, now,
|
||||
)
|
||||
if err != nil {
|
||||
return model.DownloadGrantRecord{}, "", err
|
||||
}
|
||||
|
||||
rec := model.DownloadGrantRecord{
|
||||
ID: id,
|
||||
ResourceType: resourceType,
|
||||
ResourceId: resourceID,
|
||||
Target: target,
|
||||
ExpiresAt: expiresAt,
|
||||
Enabled: true,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
return rec, token, nil
|
||||
}
|
||||
|
||||
func (r *GrantRepo) List() ([]model.DownloadGrantRecord, error) {
|
||||
var rows []grantRow
|
||||
if err := r.db.Select(&rows, "SELECT * FROM download_grants ORDER BY created_at DESC"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]model.DownloadGrantRecord, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
result = append(result, grantFromRow(row))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *GrantRepo) Get(id string) (*model.DownloadGrantRecord, error) {
|
||||
var row grantRow
|
||||
if err := r.db.Get(&row, "SELECT * FROM download_grants WHERE id = ?", id); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
rec := grantFromRow(row)
|
||||
return &rec, nil
|
||||
}
|
||||
|
||||
// GetSnapshot returns the grant record with the token hash for snapshot/restore.
|
||||
func (r *GrantRepo) GetSnapshot(id string) (map[string]any, error) {
|
||||
var row grantRow
|
||||
if err := r.db.Get(&row, "SELECT * FROM download_grants WHERE id = ?", id); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
snapshot := map[string]any{
|
||||
"id": row.ID,
|
||||
"tokenHash": row.TokenHash,
|
||||
"resourceType": row.ResourceType,
|
||||
"resourceId": row.ResourceID,
|
||||
"target": row.Target,
|
||||
"expiresAt": row.ExpiresAt,
|
||||
"enabled": row.Enabled != 0,
|
||||
"createdAt": row.CreatedAt,
|
||||
"updatedAt": row.UpdatedAt,
|
||||
}
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func (r *GrantRepo) Update(id string, enabled *bool, expiresAt *int64) (*model.DownloadGrantRecord, error) {
|
||||
existing, err := r.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing == nil {
|
||||
return nil, nil
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
if enabled != nil {
|
||||
existing.Enabled = *enabled
|
||||
}
|
||||
if expiresAt != nil {
|
||||
existing.ExpiresAt = expiresAt
|
||||
}
|
||||
// If expiresAt is explicitly set to 0, treat as nil (never expire)
|
||||
if expiresAt != nil && *expiresAt == 0 {
|
||||
existing.ExpiresAt = nil
|
||||
}
|
||||
|
||||
_, err = r.db.Exec(
|
||||
"UPDATE download_grants SET enabled = ?, expires_at = ?, updated_at = ? WHERE id = ?",
|
||||
boolToInt(existing.Enabled), existing.ExpiresAt, now, id,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return existing, nil
|
||||
}
|
||||
|
||||
func (r *GrantRepo) Delete(id string) error {
|
||||
_, err := r.db.Exec("DELETE FROM download_grants WHERE id = ?", id)
|
||||
return err
|
||||
}
|
||||
|
||||
// AuthorizeScoped checks if a token is valid for a scoped download.
|
||||
func (r *GrantRepo) AuthorizeScoped(token, resourceType, resourceID, target string) bool {
|
||||
if token == "" {
|
||||
return false
|
||||
}
|
||||
tokenHash := util.SHA256Hex(token)
|
||||
var row grantRow
|
||||
err := r.db.Get(&row,
|
||||
`SELECT * FROM download_grants WHERE token_hash = ? AND enabled = 1 AND resource_type = ? AND resource_id = ? LIMIT 1`,
|
||||
tokenHash, resourceType, resourceID,
|
||||
)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if row.ExpiresAt != nil && *row.ExpiresAt <= time.Now().UnixMilli() {
|
||||
return false
|
||||
}
|
||||
restrictedTarget := model.NormalizeTargetAlias(row.Target)
|
||||
return restrictedTarget == "" || restrictedTarget == target
|
||||
}
|
||||
|
||||
// RestoreFromSnapshot inserts a grant from a recycled snapshot.
|
||||
// Per review-resolution #38: restores tokenHash to download_grants table.
|
||||
func (r *GrantRepo) RestoreFromSnapshot(snapshot map[string]any) error {
|
||||
now := time.Now().UnixMilli()
|
||||
id := getString(snapshot, "id")
|
||||
tokenHash := getString(snapshot, "tokenHash")
|
||||
resourceType := getString(snapshot, "resourceType")
|
||||
resourceID := getString(snapshot, "resourceId")
|
||||
if resourceType != "collection" {
|
||||
resourceType = "source"
|
||||
}
|
||||
target := getString(snapshot, "target")
|
||||
enabled := true
|
||||
if e, ok := snapshot["enabled"].(bool); ok && !e {
|
||||
enabled = false
|
||||
}
|
||||
var expiresAt *int64
|
||||
if e, ok := snapshot["expiresAt"]; ok && e != nil {
|
||||
if n, ok := e.(float64); ok && n > 0 {
|
||||
v := int64(n)
|
||||
expiresAt = &v
|
||||
}
|
||||
}
|
||||
createdAt := getInt64(snapshot, "createdAt")
|
||||
if createdAt == 0 {
|
||||
createdAt = now
|
||||
}
|
||||
|
||||
_, err := r.db.Exec(
|
||||
`INSERT INTO download_grants (id, token_hash, resource_type, resource_id, target, expires_at, enabled, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
id, tokenHash, resourceType, resourceID, target, expiresAt, boolToInt(enabled), createdAt, now,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func grantFromRow(row grantRow) model.DownloadGrantRecord {
|
||||
resourceType := "source"
|
||||
if row.ResourceType == "collection" {
|
||||
resourceType = "collection"
|
||||
}
|
||||
return model.DownloadGrantRecord{
|
||||
ID: row.ID,
|
||||
ResourceType: resourceType,
|
||||
ResourceId: row.ResourceID,
|
||||
Target: row.Target,
|
||||
ExpiresAt: row.ExpiresAt,
|
||||
Enabled: row.Enabled != 0,
|
||||
CreatedAt: row.CreatedAt,
|
||||
UpdatedAt: row.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func getString(m map[string]any, key string) string {
|
||||
if v, ok := m[key]; ok {
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getInt64(m map[string]any, key string) int64 {
|
||||
if v, ok := m[key]; ok {
|
||||
switch n := v.(type) {
|
||||
case int64:
|
||||
return n
|
||||
case float64:
|
||||
return int64(n)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1,25 +1,7 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS download_grants (
|
||||
id TEXT PRIMARY KEY,
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
resource_type TEXT NOT NULL CHECK (resource_type IN ('source', 'collection')),
|
||||
resource_id TEXT NOT NULL,
|
||||
target TEXT NOT NULL DEFAULT '',
|
||||
expires_at INTEGER,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_download_grants_token_hash
|
||||
ON download_grants(token_hash);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_download_grants_resource
|
||||
ON download_grants(resource_type, resource_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recycle_bin (
|
||||
id TEXT PRIMARY KEY,
|
||||
resource_type TEXT NOT NULL CHECK (resource_type IN ('source', 'collection', 'template', 'share')),
|
||||
resource_type TEXT NOT NULL CHECK (resource_type IN ('source', 'collection', 'template')),
|
||||
resource_id TEXT NOT NULL,
|
||||
snapshot_json TEXT NOT NULL,
|
||||
deleted_at INTEGER NOT NULL
|
||||
|
||||
@@ -212,271 +212,6 @@ func TestTemplateDelete(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- GrantRepo: Get, GetSnapshot, Update, Delete, RestoreFromSnapshot ---
|
||||
|
||||
func TestGrantGet(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
rec, _, _ := repo.Create("source", "src1", "mihomo", nil)
|
||||
|
||||
got, err := repo.Get(rec.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("get failed: %v", err)
|
||||
}
|
||||
if got == nil {
|
||||
t.Fatal("expected non-nil grant")
|
||||
}
|
||||
if got.ResourceType != "source" {
|
||||
t.Errorf("expected resourceType source, got %s", got.ResourceType)
|
||||
}
|
||||
if got.ResourceId != "src1" {
|
||||
t.Errorf("expected resourceId src1, got %s", got.ResourceId)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantGet_NotFound(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
got, err := repo.Get("nonexistent")
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error for not found, got %v", err)
|
||||
}
|
||||
if got != nil {
|
||||
t.Error("expected nil for not found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantGetSnapshot(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
rec, _, _ := repo.Create("source", "src1", "mihomo", nil)
|
||||
|
||||
snap, err := repo.GetSnapshot(rec.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("getSnapshot failed: %v", err)
|
||||
}
|
||||
if snap == nil {
|
||||
t.Fatal("expected non-nil snapshot")
|
||||
}
|
||||
if snap["id"] != rec.ID {
|
||||
t.Errorf("expected id %s, got %v", rec.ID, snap["id"])
|
||||
}
|
||||
if snap["resourceType"] != "source" {
|
||||
t.Errorf("expected resourceType source, got %v", snap["resourceType"])
|
||||
}
|
||||
if snap["enabled"] != true {
|
||||
t.Errorf("expected enabled true, got %v", snap["enabled"])
|
||||
}
|
||||
if snap["tokenHash"] == "" {
|
||||
t.Error("expected non-empty tokenHash")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantGetSnapshot_NotFound(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
snap, err := repo.GetSnapshot("nonexistent")
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got %v", err)
|
||||
}
|
||||
if snap != nil {
|
||||
t.Error("expected nil snapshot for not found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantUpdate(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
rec, _, _ := repo.Create("source", "src1", "mihomo", nil)
|
||||
|
||||
// Disable
|
||||
enabled := false
|
||||
updated, err := repo.Update(rec.ID, &enabled, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("update failed: %v", err)
|
||||
}
|
||||
if updated.Enabled {
|
||||
t.Error("expected enabled false after update")
|
||||
}
|
||||
|
||||
// Set expiry
|
||||
exp := int64(9999999999000)
|
||||
updated, err = repo.Update(rec.ID, nil, &exp)
|
||||
if err != nil {
|
||||
t.Fatalf("update expiry failed: %v", err)
|
||||
}
|
||||
if updated.ExpiresAt == nil || *updated.ExpiresAt != exp {
|
||||
t.Errorf("expected expiresAt %d, got %v", exp, updated.ExpiresAt)
|
||||
}
|
||||
|
||||
// Set expiry to 0 -> treated as nil (never expire)
|
||||
zero := int64(0)
|
||||
updated, err = repo.Update(rec.ID, nil, &zero)
|
||||
if err != nil {
|
||||
t.Fatalf("update expiry zero failed: %v", err)
|
||||
}
|
||||
if updated.ExpiresAt != nil {
|
||||
t.Errorf("expected nil expiresAt for 0, got %v", updated.ExpiresAt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantUpdate_NotFound(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
updated, err := repo.Update("nonexistent", nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil error, got %v", err)
|
||||
}
|
||||
if updated != nil {
|
||||
t.Error("expected nil for not found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantDelete(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
rec, _, _ := repo.Create("source", "src1", "mihomo", nil)
|
||||
|
||||
err := repo.Delete(rec.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("delete failed: %v", err)
|
||||
}
|
||||
got, _ := repo.Get(rec.ID)
|
||||
if got != nil {
|
||||
t.Error("expected nil after delete")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantRestoreFromSnapshot(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
|
||||
snapshot := map[string]any{
|
||||
"id": "restored-grant",
|
||||
"tokenHash": "abc123",
|
||||
"resourceType": "collection",
|
||||
"resourceId": "col1",
|
||||
"target": "surge",
|
||||
"enabled": true,
|
||||
"createdAt": float64(1000),
|
||||
}
|
||||
err := repo.RestoreFromSnapshot(snapshot)
|
||||
if err != nil {
|
||||
t.Fatalf("restore failed: %v", err)
|
||||
}
|
||||
got, _ := repo.Get("restored-grant")
|
||||
if got == nil {
|
||||
t.Fatal("expected restored grant")
|
||||
}
|
||||
if got.ResourceType != "collection" {
|
||||
t.Errorf("expected resourceType collection, got %s", got.ResourceType)
|
||||
}
|
||||
if got.Target != "surge" {
|
||||
t.Errorf("expected target surge, got %s", got.Target)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantRestoreFromSnapshot_DefaultsAndExpiry(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
|
||||
// resourceType not "collection" -> defaults to "source"; enabled false; expiresAt positive
|
||||
snapshot := map[string]any{
|
||||
"id": "grant-defaults",
|
||||
"tokenHash": "hash2",
|
||||
"resourceType": "source",
|
||||
"resourceId": "src1",
|
||||
"target": "",
|
||||
"enabled": false,
|
||||
"expiresAt": float64(5000),
|
||||
}
|
||||
err := repo.RestoreFromSnapshot(snapshot)
|
||||
if err != nil {
|
||||
t.Fatalf("restore failed: %v", err)
|
||||
}
|
||||
got, _ := repo.Get("grant-defaults")
|
||||
if got == nil {
|
||||
t.Fatal("expected restored grant")
|
||||
}
|
||||
if got.ResourceType != "source" {
|
||||
t.Errorf("expected source, got %s", got.ResourceType)
|
||||
}
|
||||
if got.Enabled {
|
||||
t.Error("expected enabled false")
|
||||
}
|
||||
if got.ExpiresAt == nil || *got.ExpiresAt != 5000 {
|
||||
t.Errorf("expected expiresAt 5000, got %v", got.ExpiresAt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantRestoreFromSnapshot_NoCreatedAt(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
|
||||
snapshot := map[string]any{
|
||||
"id": "grant-no-created",
|
||||
"tokenHash": "hash3",
|
||||
"resourceType": "source",
|
||||
"resourceId": "src1",
|
||||
}
|
||||
err := repo.RestoreFromSnapshot(snapshot)
|
||||
if err != nil {
|
||||
t.Fatalf("restore failed: %v", err)
|
||||
}
|
||||
got, _ := repo.Get("grant-no-created")
|
||||
if got == nil {
|
||||
t.Fatal("expected restored grant")
|
||||
}
|
||||
if got.CreatedAt == 0 {
|
||||
t.Error("expected non-zero createdAt (defaulted to now)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantAuthorizeScoped_EmptyToken(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
if repo.AuthorizeScoped("", "source", "src1", "mihomo") {
|
||||
t.Error("expected false for empty token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantAuthorizeScoped_ExpiredGrant(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
exp := time.Now().UnixMilli() - 1000
|
||||
rec, token, _ := repo.Create("source", "src1", "mihomo", &exp)
|
||||
_ = rec
|
||||
if repo.AuthorizeScoped(token, "source", "src1", "mihomo") {
|
||||
t.Error("expected false for expired grant")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantAuthorizeScoped_UnrestrictedTarget(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
// target = "" means unrestricted
|
||||
_, token, _ := repo.Create("source", "src1", "", nil)
|
||||
if !repo.AuthorizeScoped(token, "source", "src1", "surge") {
|
||||
t.Error("expected true for unrestricted target")
|
||||
}
|
||||
if !repo.AuthorizeScoped(token, "source", "src1", "mihomo") {
|
||||
t.Error("expected true for unrestricted target (mihomo)")
|
||||
}
|
||||
}
|
||||
|
||||
// --- RecycleRepo.parseSnapshot edge cases (via List/Get) ---
|
||||
|
||||
func TestParseSnapshot_Empty(t *testing.T) {
|
||||
|
||||
@@ -178,7 +178,7 @@ func TestSettingsCRUD(t *testing.T) {
|
||||
|
||||
// Update
|
||||
updated, err := repo.Update(map[string]any{
|
||||
"theme": map[string]any{"name": "dark"},
|
||||
"theme": map[string]any{"name": "dark"},
|
||||
"appName": "MyStore",
|
||||
})
|
||||
if err != nil {
|
||||
@@ -198,48 +198,6 @@ func TestSettingsCRUD(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantCRUD(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
repo := NewGrantRepo(db)
|
||||
|
||||
// Create
|
||||
grant, token, err := repo.Create("source", "test-src", "mihomo", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("create failed: %v", err)
|
||||
}
|
||||
if token == "" {
|
||||
t.Error("expected non-empty token")
|
||||
}
|
||||
if grant.ID == "" {
|
||||
t.Error("expected non-empty grant id")
|
||||
}
|
||||
|
||||
// List
|
||||
list, err := repo.List()
|
||||
if err != nil {
|
||||
t.Fatalf("list failed: %v", err)
|
||||
}
|
||||
if len(list) != 1 {
|
||||
t.Errorf("expected 1 grant, got %d", len(list))
|
||||
}
|
||||
|
||||
// Authorize with correct token
|
||||
if !repo.AuthorizeScoped(token, "source", "test-src", "mihomo") {
|
||||
t.Error("expected authorization to succeed")
|
||||
}
|
||||
|
||||
// Authorize with wrong resource
|
||||
if repo.AuthorizeScoped(token, "collection", "test-src", "mihomo") {
|
||||
t.Error("expected authorization to fail for wrong resource type")
|
||||
}
|
||||
|
||||
// Authorize with wrong target
|
||||
if repo.AuthorizeScoped(token, "source", "test-src", "surge") {
|
||||
t.Error("expected authorization to fail for wrong target")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheCRUD(t *testing.T) {
|
||||
db := testDB(t)
|
||||
defer db.Close()
|
||||
|
||||
Reference in New Issue
Block a user