示例#1
0
async def _check_reposet(
    request: AthenianWebRequest,
    sdb_conn: Optional[databases.core.Connection],
    account: int,
    body: List[str],
) -> List[str]:
    service = None
    repos = set()
    for repo in body:
        for key, prefix in PREFIXES.items():
            if repo.startswith(prefix):
                if service is None:
                    service = key
                elif service != key:
                    raise ResponseError(
                        BadRequestError(detail="mixed services: %s, %s" %
                                        (service, key), ))
                repos.add(repo[len(prefix):])
    if service is None:
        raise ResponseError(
            BadRequestError(
                detail=
                "repository prefixes do not match to any supported service", ))
    checker = await access_classes[service](account, sdb_conn, request.mdb,
                                            request.cache).load()
    denied = await checker.check(repos)
    if denied:
        raise ResponseError(
            ForbiddenError(
                detail="the following repositories are access denied for %s: %s"
                % (service, denied), ))
    return sorted(set(body))
示例#2
0
async def create_reposet(request: AthenianWebRequest,
                         body: dict) -> web.Response:
    """Create a repository set.

    :param body: List of repositories to group.
    """
    body = RepositorySetCreateRequest.from_dict(body)
    user = request.uid
    account = body.account
    async with request.sdb.connection() as sdb_conn:
        try:
            adm = await get_user_account_status(user, account, sdb_conn,
                                                request.cache)
        except ResponseError as e:
            return e.response
        if not adm:
            return ResponseError(
                ForbiddenError(
                    detail="User %s is not an admin of the account %d" %
                    (user, account))).response
        try:
            items = await _check_reposet(request, sdb_conn, body.account,
                                         body.items)
        except ResponseError as e:
            return e.response
        rs = RepositorySet(owner=account, items=items).create_defaults()
        rid = await sdb_conn.execute(
            insert(RepositorySet).values(rs.explode()))
        return response(CreatedIdentifier(rid))
示例#3
0
async def update_reposet(request: AthenianWebRequest, id: int,
                         body: List[str]) -> web.Response:
    """Update a repository set.

    :param id: Numeric identifier of the repository set to update.
    :type id: int
    :param body: New list of repositories in the group.
    """
    async with request.sdb.connection() as sdb_conn:
        try:
            rs, is_admin = await fetch_reposet(id, [RepositorySet],
                                               request.uid, sdb_conn,
                                               request.cache)
        except ResponseError as e:
            return e.response
        if not is_admin:
            return ResponseError(
                ForbiddenError(detail="User %s may not modify reposet %d" %
                               (request.uid, id))).response
        try:
            body = await _check_reposet(request, sdb_conn, id, body)
        except ResponseError as e:
            return e.response
        rs.items = body
        rs.refresh()
        await sdb_conn.execute(
            update(RepositorySet).where(RepositorySet.id == id).values(
                rs.explode()))
        return web.json_response(body, status=200)
示例#4
0
async def _resolve_repos(
    filt: Union[FilterContribsOrReposRequest, FilterPullRequestsRequest],
    uid: str,
    native_uid: str,
    sdb_conn: Union[databases.core.Connection, databases.Database],
    mdb_conn: Union[databases.core.Connection, databases.Database],
    cache: Optional[aiomcache.Client],
) -> List[str]:
    status = await sdb_conn.fetch_one(
        select([UserAccount.is_admin]).where(
            and_(UserAccount.user_id == uid,
                 UserAccount.account_id == filt.account)))
    if status is None:
        raise ResponseError(
            ForbiddenError(detail="User %s is forbidden to access account %d" %
                           (uid, filt.account)))
    check_access = True
    if not filt.in_:
        rss = await load_account_reposets(filt.account, native_uid,
                                          [RepositorySet.id], sdb_conn,
                                          mdb_conn, cache)
        filt.in_ = ["{%d}" % rss[0][RepositorySet.id.key]]
        check_access = False
    repos = set(
        chain.from_iterable(await asyncio.gather(*[
            resolve_reposet(r, ".in[%d]" %
                            i, uid, filt.account, sdb_conn, cache)
            for i, r in enumerate(filt.in_)
        ])))
    prefix = "github.com/"
    repos = [r[r.startswith(prefix) and len(prefix):] for r in repos]
    if check_access:
        checker = await access_classes["github"](filt.account, sdb_conn,
                                                 mdb_conn, cache).load()
        denied = await checker.check(set(repos))
        if denied:
            raise ResponseError(
                ForbiddenError(
                    detail=
                    "the following repositories are access denied for %s: %s" %
                    ("github.com/", denied), ))
    return repos
示例#5
0
async def delete_reposet(request: AthenianWebRequest, id: int) -> web.Response:
    """Delete a repository set.

    :param id: Numeric identifier of the repository set to delete.
    :type id: int
    """
    try:
        _, is_admin = await fetch_reposet(id, [], request.uid, request.sdb,
                                          request.cache)
    except ResponseError as e:
        return e.response
    if not is_admin:
        return ResponseError(
            ForbiddenError(detail="User %s may not modify reposet %d" %
                           (request.uid, id))).response
    await request.sdb.execute(
        delete(RepositorySet).where(RepositorySet.id == id))
    return web.Response(status=200)
示例#6
0
async def get_account(request: AthenianWebRequest, id: int) -> web.Response:
    """Return details about the current account."""
    user_id = request.uid
    users = await request.sdb.fetch_all(
        select([UserAccount]).where(UserAccount.account_id == id))
    for user in users:
        if user[UserAccount.user_id.key] == user_id:
            break
    else:
        return ResponseError(
            ForbiddenError(
                detail="User %s is not allowed to access account %d" %
                (user_id, id))).response
    admins = []
    regulars = []
    for user in users:
        role = admins if user[UserAccount.is_admin.key] else regulars
        role.append(user[UserAccount.user_id.key])
    users = await request.auth.get_users(regulars + admins)
    account = Account(regulars=[users[k] for k in regulars if k in users],
                      admins=[users[k] for k in admins if k in users])
    return response(account)
示例#7
0
async def resolve_reposet(
    repo: str,
    pointer: str,
    uid: str,
    account: int,
    db: Union[databases.core.Connection, databases.Database],
    cache: Optional[aiomcache.Client],
) -> List[str]:
    """
    Dereference the repository sets.

    If `repo` is a regular repository, return `[repo]`. Otherwise, return the list of \
    repositories by the parsed ID from the database.
    """
    if not repo.startswith("{"):
        return [repo]
    if not repo.endswith("}"):
        raise ResponseError(
            InvalidRequestError(
                detail="repository set format is invalid: %s" % repo,
                pointer=pointer,
            ))
    try:
        set_id = int(repo[1:-1])
    except ValueError:
        raise ResponseError(
            InvalidRequestError(
                detail="repository set identifier is invalid: %s" % repo,
                pointer=pointer,
            ))
    rs, _ = await fetch_reposet(set_id, [RepositorySet.items], uid, db, cache)
    if rs.owner != account:
        raise ResponseError(
            ForbiddenError(
                detail=
                "User %s is not allowed to reference reposet %d in this query"
                % (uid, set_id)))
    return rs.items
示例#8
0
async def become_user(request: AthenianWebRequest,
                      id: str = "") -> web.Response:
    """God mode ability to turn into any user. The current user must be marked internally as \
    a super admin."""
    user_id = getattr(request, "god_id", None)
    if user_id is None:
        return ResponseError(
            ForbiddenError(detail="User %s is not allowed to mutate" %
                           user_id)).response
    async with request.sdb.connection() as conn:
        if id and (await conn.fetch_one(
                select([UserAccount]).where(UserAccount.user_id == id)
        )) is None:
            return ResponseError(
                NotFoundError(detail="User %s does not exist" % id)).response
        god = await conn.fetch_one(select([God]).where(God.user_id == user_id))
        god = God(**god).refresh()
        god.mapped_id = id or None
        await conn.execute(
            update(God).where(God.user_id == user_id).values(god.explode()))
    user = await (await
                  request.auth.get_user(id
                                        or user_id)).load_accounts(request.sdb)
    return response(user)