Use Gitea scope permission mask

This commit is contained in:
mpabi
2026-04-26 21:42:25 +02:00
parent 8c0f95d996
commit e9933d7385
4 changed files with 62 additions and 22 deletions
+2 -1
View File
@@ -168,7 +168,8 @@ logiczny remote tokena.
`token_ref` laczy nazwe tokena z markerem po prawej stronie: `*` oznacza, ze
remote i `tokens.json` sa zgodne oraz uprawnienia zostaly wczytane, `R` oznacza
token tylko w remote, a `S` token tylko w `tokens.json`. Kolumny `scope`, `org`
i `repo` sa maskami uprawnien; bez `*` maja wartosc `?????` albo `????`.
i `repo` sa maskami uprawnien; bez `*` maja wartosc `?????????`, `?????`
albo `????`.
Zapis z remote do `tokens.json` oraz odczyt `valid` i uprawnien z API robi
dopiero `tokens update --from remotes`.
Kolumna `valid` oznacza, czy token zostal zaakceptowany przez API teraz.
+24 -4
View File
@@ -36,7 +36,7 @@ Aktualny format to `version: 3`. Glownym rekordem jest token. `server`, `user`,
},
"user": "u1",
"valid": "forever",
"scope": "+---+",
"scope": "-----w---",
"remotes": [
{
"name": "r1",
@@ -69,7 +69,7 @@ Pola wzbogacane przez API przy `tokens update --from remotes`:
- `user` - login wlasciciela tokena odczytany z API
- `valid` - `forever`, data `expires_at`, `invalid`, `?` albo `!`
- `scope` - maska scope tokena
- `scope` - maska scope tokena w kolejnosci `aAimnopru`
- `remotes[].org_perm` - maska praw w organizacji
- `remotes[].repo_perm` - maska praw w repo
@@ -95,11 +95,31 @@ wartosc `?`, bo launcher nie pokazuje metadanych API dla niesparowanych wpisow.
Naglowki masek:
- `scope`: `awrop-`
- `scope`: `aAimnopru`
- `org`: `oawrc-`
- `repo`: `oawr--`
Znaki w wartosciach:
Kategorie `scope`:
- `a` - activitypub
- `A` - admin
- `i` - issue
- `m` - misc
- `n` - notification
- `o` - organization
- `p` - package
- `r` - repository
- `u` - user
Znaki w `scope`:
- `w` - read/write
- `r` - read
- `-` - no access
- `?` - nie wczytano
- `!` - blad wczytania
Znaki w `org` i `repo`:
- `+` - flaga wlaczona
- `-` - flaga wylaczona
+1 -1
View File
@@ -91,7 +91,7 @@
},
"scope": {
"type": "string",
"pattern": "^[+?!-]{5}$"
"pattern": "^[rw?!-]{9}$"
},
"expires_at": {
"type": "string"
+35 -16
View File
@@ -388,6 +388,10 @@ def normalize_remote_record(raw_remote: dict) -> dict | None:
return remote_record
def valid_mask(raw_value: str, allowed: str, width: int) -> bool:
return len(raw_value) == width and all(char in allowed for char in raw_value)
def normalize_v3_token(config: WorkspaceConfig, raw_token: dict) -> dict | None:
if not isinstance(raw_token, dict):
return None
@@ -409,10 +413,13 @@ def normalize_v3_token(config: WorkspaceConfig, raw_token: dict) -> dict | None:
"server": server_record,
"remotes": [],
}
for field_name in ["user", "valid", "scope", "expires_at"]:
for field_name in ["user", "valid", "expires_at"]:
field_value = raw_token.get(field_name)
if isinstance(field_value, str) and field_value:
token_record[field_name] = field_value
scope_value = raw_token.get("scope")
if isinstance(scope_value, str) and valid_mask(scope_value, "rw?!-", 9):
token_record["scope"] = scope_value
raw_remotes = raw_token.get("remotes", [])
if isinstance(raw_remotes, dict):
@@ -1070,13 +1077,13 @@ TOKEN_COLUMNS = [
("token_ref", "token_ref", TOKEN_REF_WIDTH),
("token", "token", 12),
("valid", "valid", 19),
("scope_mask", "scope", 6),
("scope_mask", "scope", 9),
("org_mask", "org", 6),
("repo_mask", "repo", 6),
]
TOKEN_SEPARATOR_OVERRIDES = {
"scope_mask": "awrop-",
"scope_mask": "aAimnopru",
"org_mask": "oawrc-",
"repo_mask": "oawr--",
}
@@ -1250,15 +1257,27 @@ def api_get_json(api_url: str, token_value: str, user_name: str = "", basic: boo
def scope_mask(scopes: list[str]) -> str:
scope_set = {scope.lower() for scope in scopes}
return "".join(
[
"+" if "all" in scope_set else "-",
"+" if "write:repository" in scope_set else "-",
"+" if "read:repository" in scope_set else "-",
"+" if {"read:organization", "write:organization"} & scope_set else "-",
"+" if "public-only" in scope_set else "-",
]
)
categories = [
"activitypub",
"admin",
"issue",
"misc",
"notification",
"organization",
"package",
"repository",
"user",
]
values = []
for category in categories:
if f"write:{category}" in scope_set:
values.append("w")
elif f"read:{category}" in scope_set:
values.append("r")
else:
values.append("-")
return "".join(values)
def org_permission_mask(org_permissions: dict) -> str:
@@ -1296,7 +1315,7 @@ def load_gitea_authz(
result = {
"ok": False,
"valid": "!",
"scope_mask": "!!!!!",
"scope_mask": "!!!!!!!!!",
"org_mask": "!!!!!",
"repo_mask": "!!!!",
"user": "",
@@ -1326,7 +1345,7 @@ def load_gitea_authz(
scopes = []
result["scope_mask"] = scope_mask([str(scope) for scope in scopes])
except (OSError, ValueError, urlerror.URLError):
result["scope_mask"] = "?????"
result["scope_mask"] = "?????????"
if user_name and owner:
org_url = f"{api_base}/users/{quote(user_name, safe='')}/orgs/{quote(owner, safe='')}/permissions"
@@ -1394,7 +1413,7 @@ def print_token_item_rows(
) -> None:
endpoint_values = endpoint_values_by_name.get(endpoint, endpoint_column_values(endpoint, None, None))
valid_value = store_row.get("valid", "?") if store_row else "?"
scope_value = store_row.get("scope_mask", "?????") if store_row else "?????"
scope_value = store_row.get("scope_mask", "?????????") if store_row else "?????????"
org_value = store_row.get("org_mask", "?????") if store_row else "?????"
repo_value = store_row.get("repo_mask", "????") if store_row else "????"
token_rows.append(
@@ -1410,7 +1429,7 @@ def print_token_item_rows(
"token_ref": format_token_ref(token_id, marker),
"token": short_secret(token_value),
"valid": valid_value or "?",
"scope_mask": scope_value or "?????",
"scope_mask": scope_value or "?????????",
"org_mask": org_value or "?????",
"repo_mask": repo_value or "????",
}