Merge pull request #24 from msys2/sig-support
packages: show who signed the package and when
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import base64
|
||||
import uuid
|
||||
import time
|
||||
from functools import cmp_to_key
|
||||
@@ -12,6 +13,7 @@ from typing import List, Set, Dict, Tuple, Optional, Type, Sequence, NamedTuple
|
||||
|
||||
from .appconfig import REPOSITORIES
|
||||
from .utils import vercmp, version_is_newer_than, extract_upstream_version
|
||||
from .pgp import parse_signature
|
||||
|
||||
|
||||
CygwinVersions = Dict[str, Tuple[str, str, str]]
|
||||
@@ -222,7 +224,7 @@ class Package:
|
||||
makedepends: List[str], md5sum: str, name: str, pgpsig: str, sha256sum: str, arch: str,
|
||||
base_url: str, repo: str, repo_variant: str, provides: List[str], conflicts: List[str], replaces: List[str],
|
||||
version: str, base: str, desc: str, groups: List[str], licenses: List[str], optdepends: List[str],
|
||||
checkdepends: List[str]) -> None:
|
||||
checkdepends: List[str], sig_data: str) -> None:
|
||||
self.builddate = int(builddate)
|
||||
self.csize = csize
|
||||
|
||||
@@ -235,6 +237,7 @@ class Package:
|
||||
r.append((first, second))
|
||||
return r
|
||||
|
||||
self.signature = parse_signature(base64.b64decode(sig_data))
|
||||
self.depends = split_depends(depends)
|
||||
self.checkdepends = split_depends(checkdepends)
|
||||
self.filename = filename
|
||||
@@ -317,7 +320,7 @@ class Package:
|
||||
d.get("%REPLACES%", []), d["%VERSION%"][0], base,
|
||||
d.get("%DESC%", [""])[0], d.get("%GROUPS%", []),
|
||||
d.get("%LICENSE%", []), d.get("%OPTDEPENDS%", []),
|
||||
d.get("%CHECKDEPENDS%", []))
|
||||
d.get("%CHECKDEPENDS%", []), d.get("%PGPSIG%", [""])[0])
|
||||
|
||||
|
||||
class Source:
|
||||
|
||||
57
app/pgp.py
Normal file
57
app/pgp.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from pgpdump import BinaryData
|
||||
from pgpdump.utils import PgpdumpException
|
||||
from datetime import datetime
|
||||
from typing import NamedTuple
|
||||
import struct
|
||||
import binascii
|
||||
|
||||
|
||||
KNOWN_KEYS = {
|
||||
"5F92EFC1A47D45A1": "Alexey Pavlov",
|
||||
"4DF3B7664CA56930": "Ray Donnelly",
|
||||
"D595C9AB2C51581E": "Martell Malone",
|
||||
"974C8BE49078F532": "David Macek",
|
||||
"FA11531AA0AA7F57": "Christoph Reiter",
|
||||
}
|
||||
|
||||
|
||||
class Signature(NamedTuple):
|
||||
keyid: str
|
||||
date: datetime
|
||||
|
||||
@property
|
||||
def url(self) -> str:
|
||||
return "http://pool.sks-keyservers.net/pks/lookup?op=vindex&fingerprint=on&search=0x" + self.keyid
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return KNOWN_KEYS.get(self.keyid.upper(), "Unknown")
|
||||
|
||||
|
||||
class SigError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def parse_signature(sig_data: bytes) -> Signature:
|
||||
date = None
|
||||
keyid = None
|
||||
|
||||
try:
|
||||
parsed = BinaryData(sig_data)
|
||||
except PgpdumpException as e:
|
||||
raise SigError(e)
|
||||
|
||||
for x in parsed.packets():
|
||||
if x.raw == 2:
|
||||
for sub in x.subpackets:
|
||||
if sub.subtype == 2:
|
||||
date = datetime.utcfromtimestamp(struct.unpack('>I', sub.data)[0])
|
||||
if sub.subtype == 16:
|
||||
keyid = binascii.hexlify(sub.data).decode()
|
||||
|
||||
if keyid is None:
|
||||
raise SigError("keyid missing")
|
||||
if date is None:
|
||||
raise SigError("date missing")
|
||||
|
||||
return Signature(keyid, date)
|
||||
@@ -43,6 +43,12 @@
|
||||
<dt class="col-sm-3 text-sm-right">Build Date:</dt>
|
||||
<dd class="col-sm-9">{{ p.builddate|timestamp }}</dd>
|
||||
|
||||
<dt class="col-sm-3 text-sm-right">Signed By:</dt>
|
||||
<dd class="col-sm-9"><a href="{{ p.signature.url }}">{{ p.signature.name }}</a></dd>
|
||||
|
||||
<dt class="col-sm-3 text-sm-right">Signature Date:</dt>
|
||||
<dd class="col-sm-9">{{ p.signature.date }}</dd>
|
||||
|
||||
<dt class="col-sm-3 text-sm-right">Package Size:</dt>
|
||||
<dd class="col-sm-9">{{ p.csize|filesize }}</dd>
|
||||
|
||||
|
||||
13
poetry.lock
generated
13
poetry.lock
generated
@@ -297,6 +297,14 @@ version = "20.4"
|
||||
pyparsing = ">=2.0.2"
|
||||
six = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "PGP packet parser library"
|
||||
name = "pgpdump"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.5"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
@@ -538,7 +546,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["jaraco.itertools", "func-timeout"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "65b0ed368759d67e2016c027ea98952449a27db72c2555fc779d54936ae4f31c"
|
||||
content-hash = "2c191d8d34f6865392bd1df633bf1ec72ea1ed51f7c6d33940b2e37679c4d78d"
|
||||
python-versions = "^3.7"
|
||||
|
||||
[metadata.files]
|
||||
@@ -707,6 +715,9 @@ packaging = [
|
||||
{file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
|
||||
{file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
|
||||
]
|
||||
pgpdump = [
|
||||
{file = "pgpdump-1.5.tar.gz", hash = "sha256:1c4700857bf7ba735b08cfe4101aa3a4f5fd839657af249c17b2697c20829668"},
|
||||
]
|
||||
pluggy = [
|
||||
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
|
||||
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
|
||||
|
||||
@@ -13,6 +13,7 @@ uvicorn = "^0.11.5"
|
||||
aiofiles = "^0.5.0"
|
||||
jinja2 = "^2.11.2"
|
||||
fastapi-etag = "^0.2.1"
|
||||
pgpdump = "^1.5"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
mypy = "^0.770"
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# type: ignore
|
||||
|
||||
import os
|
||||
import base64
|
||||
import datetime
|
||||
|
||||
import respx
|
||||
import pytest
|
||||
from app import app
|
||||
from app.fetch import parse_cygwin_versions
|
||||
from app.pgp import parse_signature, SigError, Signature
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@@ -81,3 +84,25 @@ def test_webhook_push(client, monkeypatch):
|
||||
r.raise_for_status()
|
||||
assert "msg" in r.json()
|
||||
assert "1234" in r.json()["msg"]
|
||||
|
||||
|
||||
EXAMPLE_SIG = (
|
||||
"iHUEABEIAB0WIQStNRxQrghXdetZMztfku/BpH1FoQUCXlOY5wAKCRBfku"
|
||||
"/BpH1FodQoAP4nQnPNLnx5MVIJgZgCwW/hplW7Ai9MqkmFBqD8/+EXfAD/"
|
||||
"Rgxtz2XH7RZ1JKh7PN5NsVz9UlBM7977PjFg9WptNGU=")
|
||||
|
||||
|
||||
def test_pgp():
|
||||
with pytest.raises(SigError):
|
||||
parse_signature(b"")
|
||||
|
||||
with pytest.raises(SigError):
|
||||
parse_signature(b"foobar")
|
||||
|
||||
data = base64.b64decode(EXAMPLE_SIG)
|
||||
sig = parse_signature(data)
|
||||
assert isinstance(sig, Signature)
|
||||
assert sig.keyid == "5f92efc1a47d45a1"
|
||||
assert sig.date == datetime.datetime(2020, 2, 24, 9, 35, 35)
|
||||
assert sig.name == "Alexey Pavlov"
|
||||
assert sig.url == "http://pool.sks-keyservers.net/pks/lookup?op=vindex&fingerprint=on&search=0x5f92efc1a47d45a1"
|
||||
|
||||
Reference in New Issue
Block a user