| 1 | // SPDX-License-Identifier: AGPL-3.0-or-later |
| 2 | |
| 3 | package policy |
| 4 | |
| 5 | // Actor is the authenticated identity asking for a decision. The web |
| 6 | // layer constructs one from middleware.CurrentUserFromContext + a |
| 7 | // suspended/admin check. SSH and HTTP git transports build their own |
| 8 | // from the resolved auth principal. |
| 9 | // |
| 10 | // An anonymous request has UserID == 0; IsAnonymous == true. Convention |
| 11 | // is that callers fill IsAnonymous explicitly even when UserID == 0 |
| 12 | // implies it — duplication is cheap and keeps the boolean visible at |
| 13 | // every call site. |
| 14 | type Actor struct { |
| 15 | UserID int64 |
| 16 | Username string |
| 17 | IsAnonymous bool |
| 18 | IsSuspended bool |
| 19 | IsSiteAdmin bool |
| 20 | // Impersonating reports whether this actor was constructed from |
| 21 | // an admin viewing-as another user. ImpersonateWriteOK enables |
| 22 | // the admin's writes during the impersonation; without it, every |
| 23 | // write action gets denied (the canonical foot-gun guard). |
| 24 | Impersonating bool |
| 25 | ImpersonateWriteOK bool |
| 26 | } |
| 27 | |
| 28 | // AnonymousActor returns the canonical anonymous Actor. Use in tests |
| 29 | // and at unauthenticated entrypoints. |
| 30 | func AnonymousActor() Actor { |
| 31 | return Actor{IsAnonymous: true} |
| 32 | } |
| 33 | |
| 34 | // UserActor wraps a logged-in user. Suspension and site-admin flags |
| 35 | // must be loaded from the DB by the caller — the policy package does |
| 36 | // not query users on its own to keep the decision pure. |
| 37 | func UserActor(userID int64, username string, suspended, siteAdmin bool) Actor { |
| 38 | return Actor{ |
| 39 | UserID: userID, |
| 40 | Username: username, |
| 41 | IsSuspended: suspended, |
| 42 | IsSiteAdmin: siteAdmin, |
| 43 | } |
| 44 | } |
| 45 |