Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions brood/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ def user_as_json_dict(user: User) -> Dict[str, Any]:
"username": user.username,
"email": user.email,
"normalized_email": user.normalized_email,
"web3_address": user.web3_address,
"verified": user.verified,
"created_at": str(user.created_at),
"updated_at": str(user.updated_at),
Expand Down
2 changes: 1 addition & 1 deletion brood/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ async def delete_token_handler(

- **target_token** (uuid, null): Token ID to revoke
"""
authorization: str = request.headers.get("Authorization")
authorization: str = request.headers.get("Authorization") # type: ignore
scheme_raw, _ = get_authorization_scheme_param(authorization)
scheme = scheme_raw.lower()
if scheme != "bearer":
Expand Down
80 changes: 70 additions & 10 deletions brood/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,26 @@
Brood CLI
"""
import argparse
from distutils.util import strtobool
import base64
import json
from typing import List
import uuid
from distutils.util import strtobool
from typing import List

from web3login.auth import to_checksum_address, verify
from web3login.exceptions import Web3VerificationError

from . import actions
from . import data
from . import exceptions
from . import subscriptions
from . import actions, data, exceptions, subscriptions
from .db import SessionLocal
from .models import (
User,
Application,
Group,
KVBrood,
Role,
TokenType,
Subscription,
SubscriptionPlan,
KVBrood,
Application,
TokenType,
User,
)


Expand Down Expand Up @@ -79,6 +80,49 @@ def users_create_handler(args: argparse.Namespace) -> None:
session.close()


def users_update_handler(args: argparse.Namespace) -> None:
"""
Handler for "user update" subcommand.
"""
if args.web3_signature is None:
raise Exception("No arguments specified to update")

session = SessionLocal()
try:
query = session.query(User).filter(User.id == args.id)
user = query.one_or_none()
if user is None:
raise Exception("User not found")

if args.web3_signature is not None:
payload_json = base64.decodebytes(args.web3_signature.encode()).decode(
"utf-8"
)
payload = json.loads(payload_json)
verified = verify(
authorization_payload=payload,
application_to_check=str(user.application_id)
if user.application_id is not None
else "",
)
if not verified:
raise Web3VerificationError("Web3 registration verification error")
web3_address = payload.get("address")
if web3_address is None:
raise Exception(
f"Web3 address in payload could not be None for user with username: {user.username}"
)
web3_address = to_checksum_address(web3_address)
query.update({User.web3_address: web3_address})

session.commit()
print_user(user)
except Exception as e:
print(e)
finally:
session.close()


def users_get_handler(args: argparse.Namespace) -> None:
"""
Handler for "users get" subcommand.
Expand Down Expand Up @@ -723,6 +767,22 @@ def main() -> None:
)
parser_users_create.set_defaults(func=users_create_handler)

parser_users_update = subcommands_users.add_parser(
"update", description="Update Brood user"
)
parser_users_update.add_argument(
"-i",
"--id",
required=True,
help="ID of the user to update",
)
parser_users_update.add_argument(
"-w",
"--web3_signature",
help="Set new web3 address with provided signature",
)
parser_users_update.set_defaults(func=users_update_handler)

parser_users_get = subcommands_users.add_parser("get", description="Get Brood user")
parser_users_get.add_argument(
"-u",
Expand Down
14 changes: 7 additions & 7 deletions brood/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ async def get_current_user(
"""
Middleware returns user if its token or web3 signature verified.
"""
authorization: str = request.headers.get("Authorization")
authorization: str = request.headers.get("Authorization") # type: ignore
scheme_raw, _ = get_authorization_scheme_param(authorization)
scheme = scheme_raw.lower()
if token is None or token == "":
raise HTTPException(status_code=404, detail="Access token not found")

signature_application: str = request.headers.get(BUGOUT_APPLICATION_ID_HEADER)
signature_application: str = request.headers.get(BUGOUT_APPLICATION_ID_HEADER) # type: ignore
application_id = None
if signature_application is not None:
try:
Expand Down Expand Up @@ -135,13 +135,13 @@ async def get_current_user_with_groups(
"""
Middleware returns user with groups it belongs if its token or web3 signature verified.
"""
authorization: str = request.headers.get("Authorization")
authorization: str = request.headers.get("Authorization") # type: ignore
scheme_raw, _ = get_authorization_scheme_param(authorization)
scheme = scheme_raw.lower()
if token is None or token == "":
raise HTTPException(status_code=404, detail="Access token not found")

signature_application: str = request.headers.get(BUGOUT_APPLICATION_ID_HEADER)
signature_application: str = request.headers.get(BUGOUT_APPLICATION_ID_HEADER) # type: ignore
application_id = None
if signature_application is not None:
try:
Expand Down Expand Up @@ -225,7 +225,7 @@ def autogenerated_user_token_check(request: Request) -> bool:
is_autogenerated_user = False
installation_token_header: Optional[str] = request.headers.get(
BOT_INSTALLATION_TOKEN_HEADER, None
)
) # type: ignore
if (
installation_token_header is not None
and BOT_INSTALLATION_TOKEN == installation_token_header
Expand Down Expand Up @@ -253,7 +253,7 @@ async def is_token_restricted_or_installation(
Because of oauth2_scheme_manual we could accept None
for follow up Bugout header check.
"""
authorization: str = request.headers.get("Authorization")
authorization: str = request.headers.get("Authorization") # type: ignore
scheme_raw, _ = get_authorization_scheme_param(authorization)
scheme = scheme_raw.lower()

Expand All @@ -276,7 +276,7 @@ async def is_token_restricted(
"""
Check if user's token is restricted or not.
"""
authorization: str = request.headers.get("Authorization")
authorization: str = request.headers.get("Authorization") # type: ignore
scheme_raw, _ = get_authorization_scheme_param(authorization)
scheme = scheme_raw.lower()

Expand Down
2 changes: 1 addition & 1 deletion brood/resources/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def acl_auth(
def acl_check(
acl: Dict[data.HolderType, List[str]],
required_scopes: Set[data.ResourcePermissions],
check_type: data.HolderType = None,
check_type: Optional[data.HolderType] = None,
) -> None:
"""
Checks if provided permissions from handler intersect with existing permissions for user/group.
Expand Down
4 changes: 2 additions & 2 deletions deploy/deploy.monolith.bash
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,5 @@ echo
echo -e "${PREFIX_INFO} Replacing existing Brood service definition with ${BROOD_SERVICE_FILE}"
chmod 644 "${SCRIPT_DIR}/${BROOD_SOURCE_SERVICE_FILE}"
cp "${SCRIPT_DIR}/${BROOD_SOURCE_SERVICE_FILE}" "/home/ubuntu/.config/systemd/user/${BROOD_SERVICE_FILE}"
XDG_RUNTIME_DIR="/run/user/$UID" systemctl --user daemon-reload
XDG_RUNTIME_DIR="/run/user/$UID" systemctl --user restart "${BROOD_SERVICE_FILE}"
XDG_RUNTIME_DIR="/run/user/1000" systemctl --user daemon-reload
XDG_RUNTIME_DIR="/run/user/1000" systemctl --user restart "${BROOD_SERVICE_FILE}"