fix: remove backward compat, migrate old access to proper RBAC grants
Removed the backward compatibility fallback that checked the old dossier_access table from CanManageDossier/CanAccessDossier - it was a security risk (hidden path that bypassed the new RBAC system). Instead, added MigrateOldAccess() that converts existing dossier_access entries to proper access grants on startup (idempotent - skips existing). Migration rules: - Self-references (accessor == target) skipped (owner access is automatic) - can_edit = 1 → "rwdm" root grant - can_edit = 0 → "r" root grant - Role set to "Migrated" for tracking Result: 12 grants migrated from old table. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
08139ada28
commit
7192f39bc1
|
|
@ -329,43 +329,13 @@ func EnsureCategoryEntry(dossierID string, category int) (string, error) {
|
|||
}
|
||||
|
||||
// CanAccessDossier returns true if accessor can read dossier (for quick checks)
|
||||
// Falls back to old dossier_access for backward compatibility
|
||||
func CanAccessDossier(accessorID, dossierID string) bool {
|
||||
// Check new RBAC system first
|
||||
if CheckAccess(accessorID, dossierID, "", 'r') == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// Fallback: check old dossier_access table
|
||||
var result []struct {
|
||||
Status int `db:"status"`
|
||||
}
|
||||
err := Query(
|
||||
"SELECT status FROM dossier_access WHERE accessor_dossier_id = ? AND target_dossier_id = ? AND status = 1",
|
||||
[]any{accessorID, dossierID},
|
||||
&result,
|
||||
)
|
||||
return err == nil && len(result) > 0 && result[0].Status == 1
|
||||
return CheckAccess(accessorID, dossierID, "", 'r') == nil
|
||||
}
|
||||
|
||||
// CanManageDossier returns true if accessor can manage permissions for dossier
|
||||
// Falls back to old dossier_access.can_edit for backward compatibility
|
||||
func CanManageDossier(accessorID, dossierID string) bool {
|
||||
// Check new RBAC system first
|
||||
if CheckAccess(accessorID, dossierID, "", 'm') == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// Fallback: check old dossier_access table
|
||||
var result []struct {
|
||||
CanEdit int `db:"can_edit"`
|
||||
}
|
||||
err := Query(
|
||||
"SELECT can_edit FROM dossier_access WHERE accessor_dossier_id = ? AND target_dossier_id = ? AND status = 1",
|
||||
[]any{accessorID, dossierID},
|
||||
&result,
|
||||
)
|
||||
return err == nil && len(result) > 0 && result[0].CanEdit == 1
|
||||
return CheckAccess(accessorID, dossierID, "", 'm') == nil
|
||||
}
|
||||
|
||||
// GrantAccess creates an access grant
|
||||
|
|
|
|||
41
lib/v2.go
41
lib/v2.go
|
|
@ -800,6 +800,47 @@ func AccessGrantRemove(ids ...string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MigrateOldAccess converts dossier_access entries to access grants (one-time migration)
|
||||
func MigrateOldAccess() int {
|
||||
type oldAccess struct {
|
||||
AccessorID string `db:"accessor_dossier_id"`
|
||||
TargetID string `db:"target_dossier_id"`
|
||||
CanEdit int `db:"can_edit"`
|
||||
}
|
||||
var entries []oldAccess
|
||||
err := Query("SELECT accessor_dossier_id, target_dossier_id, can_edit FROM dossier_access WHERE status = 1", nil, &entries)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
migrated := 0
|
||||
for _, e := range entries {
|
||||
// Skip self-references (owner access is automatic)
|
||||
if e.AccessorID == e.TargetID {
|
||||
continue
|
||||
}
|
||||
// Skip if grant already exists
|
||||
existing, _ := AccessGrantList(&PermissionFilter{DossierID: e.TargetID, GranteeID: e.AccessorID})
|
||||
if len(existing) > 0 {
|
||||
continue
|
||||
}
|
||||
// Create root-level grant
|
||||
ops := "r"
|
||||
if e.CanEdit == 1 {
|
||||
ops = "rwdm"
|
||||
}
|
||||
AccessGrantWrite(&Access{
|
||||
DossierID: e.TargetID,
|
||||
GranteeID: e.AccessorID,
|
||||
EntryID: "",
|
||||
Role: "Migrated",
|
||||
Ops: ops,
|
||||
})
|
||||
migrated++
|
||||
}
|
||||
return migrated
|
||||
}
|
||||
|
||||
// AccessGrantGet retrieves a single access grant by ID
|
||||
func AccessGrantGet(id string) (*Access, error) {
|
||||
a := &Access{}
|
||||
|
|
|
|||
|
|
@ -2097,6 +2097,12 @@ func main() {
|
|||
fmt.Printf("Warning: could not ensure bridge client: %v\n", err)
|
||||
}
|
||||
fmt.Println("lib.DBInit successful")
|
||||
lib.ConfigInit()
|
||||
|
||||
// Migrate old dossier_access to new RBAC grants (idempotent)
|
||||
if n := lib.MigrateOldAccess(); n > 0 {
|
||||
fmt.Printf("Migrated %d access grants from dossier_access\n", n)
|
||||
}
|
||||
|
||||
loadTranslations()
|
||||
lib.TranslateInit("lang") // also init lib translations for CategoryTranslate
|
||||
|
|
|
|||
Loading…
Reference in New Issue