add key-import button to interface

This commit is contained in:
2022-11-25 02:12:05 +02:00
parent 577bd9e5f8
commit 9fa1fa108f
41 changed files with 727 additions and 177 deletions

View File

@@ -20,16 +20,18 @@
from __future__ import annotations
from aiohttp.web import Request, View
from typing import Any, Dict, List, Optional, Type
from typing import Any, Callable, Dict, List, Optional, Type, TypeVar
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.spawn import Spawn
from ahriman.core.status.watcher import Watcher
from ahriman.models.user_access import UserAccess
T = TypeVar("T", str, List[str])
class BaseView(View):
"""
base web view to make things typed
@@ -46,17 +48,6 @@ class BaseView(View):
configuration: Configuration = self.request.app["configuration"]
return configuration
@property
def database(self) -> SQLite:
"""
get database instance
Returns:
SQLite: database instance
"""
database: SQLite = self.request.app["database"]
return database
@property
def service(self) -> Watcher:
"""
@@ -104,6 +95,29 @@ class BaseView(View):
permission: UserAccess = getattr(cls, f"{request.method.upper()}_PERMISSION", UserAccess.Full)
return permission
@staticmethod
def get_non_empty(extractor: Callable[[str], Optional[T]], key: str) -> T:
"""
get non-empty value from request parameters
Args:
extractor(Callable[[str], T]): function to get value by key
key(str): key to extract value
Returns:
T: extracted values if it is presented and not empty
Raises:
KeyError: in case if key was not found or value is empty
"""
try:
value = extractor(key)
if not value:
raise KeyError(key)
except Exception:
raise KeyError(f"Key {key} is missing or empty")
return value
async def extract_data(self, list_keys: Optional[List[str]] = None) -> Dict[str, Any]:
"""
extract json data from either json or form data

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPNoContent
from aiohttp.web import HTTPBadRequest, HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
@@ -62,8 +62,11 @@ class AddView(BaseView):
< Server: Python/3.10 aiohttp/3.8.3
<
"""
data = await self.extract_data(["packages"])
packages = data.get("packages", [])
try:
data = await self.extract_data(["packages"])
packages = self.get_non_empty(lambda key: [package for package in data[key] if package], "packages")
except Exception as e:
raise HTTPBadRequest(reason=str(e))
self.spawner.packages_add(packages, now=True)

View File

@@ -0,0 +1,121 @@
#
# Copyright (c) 2021-2022 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
class PGPView(BaseView):
"""
pgp key management web view
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
POST_PERMISSION = UserAccess.Full
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Reporter
async def get(self) -> Response:
"""
retrieve key from the key server. It supports two query parameters: ``key`` - pgp key fingerprint and
``server`` which points to valid PGP key server
Returns:
Response: 200 with key body on success
Raises:
HTTPBadRequest: if bad data is supplied
HTTPNotFound: if key wasn't found or service was unable to fetch it
Examples:
Example of command by using curl::
$ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/service/pgp?key=0xE989490C&server=keyserver.ubuntu.com'
> GET /api/v1/service/pgp?key=0xE989490C&server=keyserver.ubuntu.com HTTP/1.1
> Host: example.com
> User-Agent: curl/7.86.0
> Accept: application/json
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Content-Length: 3275
< Date: Fri, 25 Nov 2022 22:54:02 GMT
< Server: Python/3.10 aiohttp/3.8.3
<
{"key": "key"}
"""
try:
key = self.get_non_empty(self.request.query.getone, "key")
server = self.get_non_empty(self.request.query.getone, "server")
except Exception as e:
raise HTTPBadRequest(reason=str(e))
try:
key = self.service.repository.sign.key_download(server, key)
except Exception:
raise HTTPNotFound()
return json_response({"key": key})
async def post(self) -> None:
"""
store key to the local service environment
JSON body must be supplied, the following model is used::
{
"key": "0x8BE91E5A773FB48AC05CC1EDBED105AED6246B39", # key fingerprint to import
"server": "keyserver.ubuntu.com" # optional pgp server address
}
Raises:
HTTPBadRequest: if bad data is supplied
HTTPNoContent: in case of success response
Examples:
Example of command by using curl::
$ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/service/pgp' -d '{"key": "0xE989490C"}'
> POST /api/v1/service/pgp HTTP/1.1
> Host: example.com
> User-Agent: curl/7.86.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 21
>
< HTTP/1.1 204 No Content
< Date: Fri, 25 Nov 2022 22:55:56 GMT
< Server: Python/3.10 aiohttp/3.8.3
<
"""
data = await self.extract_data()
try:
key = self.get_non_empty(data.get, "key")
except Exception as e:
raise HTTPBadRequest(reason=str(e))
self.spawner.key_import(key, data.get("server"))
raise HTTPNoContent()

View File

@@ -65,7 +65,7 @@ class RemoveView(BaseView):
"""
try:
data = await self.extract_data(["packages"])
packages = data["packages"]
packages = self.get_non_empty(lambda key: [package for package in data[key] if package], "packages")
except Exception as e:
raise HTTPBadRequest(reason=str(e))

View File

@@ -65,7 +65,7 @@ class RequestView(BaseView):
"""
try:
data = await self.extract_data(["packages"])
packages = data["packages"]
packages = self.get_non_empty(lambda key: [package for package in data[key] if package], "packages")
except Exception as e:
raise HTTPBadRequest(reason=str(e))

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPNotFound, Response, json_response
from aiohttp.web import HTTPBadRequest, HTTPNotFound, Response, json_response
from typing import Callable, List
from ahriman.core.alpm.remote import AUR
@@ -45,6 +45,7 @@ class SearchView(BaseView):
Response: 200 with found package bases and descriptions sorted by base
Raises:
HTTPBadRequest: in case if bad data is supplied
HTTPNotFound: if no packages found
Examples:
@@ -64,8 +65,12 @@ class SearchView(BaseView):
<
[{"package": "ahriman", "description": "ArcH linux ReposItory MANager"}, {"package": "ahriman-git", "description": "ArcH Linux ReposItory MANager"}]
"""
search: List[str] = self.request.query.getall("for", default=[])
packages = AUR.multisearch(*search, pacman=self.service.repository.pacman)
try:
search: List[str] = self.get_non_empty(lambda key: self.request.query.getall(key, default=[]), "for")
packages = AUR.multisearch(*search, pacman=self.service.repository.pacman)
except Exception as e:
raise HTTPBadRequest(reason=str(e))
if not packages:
raise HTTPNotFound(reason=f"No packages found for terms: {search}")

View File

@@ -0,0 +1,59 @@
#
# Copyright (c) 2021-2022 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
class UpdateView(BaseView):
"""
update repository web view
Attributes:
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
POST_PERMISSION = UserAccess.Full
async def post(self) -> None:
"""
run repository update. No parameters supported here
Raises:
HTTPNoContent: in case of success response
Examples:
Example of command by using curl::
$ curl -v -XPOST 'http://example.com/api/v1/service/update'
> POST /api/v1/service/update HTTP/1.1
> Host: example.com
> User-Agent: curl/7.86.0
> Accept: */*
>
< HTTP/1.1 204 No Content
< Date: Fri, 25 Nov 2022 22:57:56 GMT
< Server: Python/3.10 aiohttp/3.8.3
<
"""
self.spawner.packages_update()
raise HTTPNoContent()

View File

@@ -17,8 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response
from aiohttp.web_exceptions import HTTPNotFound
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
from ahriman.core.exceptions import UnknownPackageError
from ahriman.models.log_record_id import LogRecordId

View File

@@ -17,8 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPFound
from aiohttp.web_exceptions import HTTPUnauthorized
from aiohttp.web import HTTPFound, HTTPUnauthorized
from ahriman.core.auth.helpers import check_authorized, forget
from ahriman.models.user_access import UserAccess