Exemple #1
0
def ssh_pubkey(PK: str = str(), user: models.User = None, **kwargs) -> None:
    if not PK:
        # If no pubkey is provided, wipe out any pubkeys the user
        # has and return out early.
        with db.begin():
            db.delete_all(user.ssh_pub_keys)
        return

    # Otherwise, parse ssh keys and their fprints out of PK.
    keys = util.parse_ssh_keys(PK.strip())
    fprints = [get_fingerprint(" ".join(k)) for k in keys]

    with db.begin():
        # Delete any existing keys we can't find.
        to_remove = user.ssh_pub_keys.filter(
            ~SSHPubKey.Fingerprint.in_(fprints))
        db.delete_all(to_remove)

        # For each key, if it does not yet exist, create it.
        for i, full_key in enumerate(keys):
            prefix, key = full_key
            exists = user.ssh_pub_keys.filter(
                SSHPubKey.Fingerprint == fprints[i]).exists()
            if not db.query(exists).scalar():
                # No public key exists, create one.
                db.create(models.SSHPubKey,
                          UserID=user.ID,
                          PubKey=" ".join([prefix, key]),
                          Fingerprint=fprints[i])
Exemple #2
0
def test_usermaint(user: User):
    """
    In this case, we first test that only the expired record gets
    updated, but the non-expired record remains untouched. After,
    we update the login time on the non-expired record and exercise
    its code path.
    """

    now = time.utcnow()
    limit_to = now - 86400 * 7
    with db.begin():
        user.LastLoginIPAddress = "127.0.0.1"
        user.LastLogin = limit_to - 666
        user.LastSSHLoginIPAddress = "127.0.0.1"
        user.LastSSHLogin = now - 10

    usermaint.main()

    assert user.LastLoginIPAddress is None
    assert user.LastSSHLoginIPAddress == "127.0.0.1"

    with db.begin():
        user.LastSSHLogin = limit_to - 666

    usermaint.main()

    assert user.LastLoginIPAddress is None
    assert user.LastSSHLoginIPAddress is None
Exemple #3
0
def test_dependency_type_creation():
    with begin():
        dependency_type = create(DependencyType, Name="Test Type")
    assert bool(dependency_type.ID)
    assert dependency_type.Name == "Test Type"
    with begin():
        delete(dependency_type)
Exemple #4
0
def test_user_credential_types(user: User):
    assert user.AccountTypeID in creds.user_developer_or_trusted_user
    assert user.AccountTypeID not in creds.trusted_user
    assert user.AccountTypeID not in creds.developer
    assert user.AccountTypeID not in creds.trusted_user_or_dev

    with db.begin():
        user.AccountTypeID = at.TRUSTED_USER_ID

    assert user.AccountTypeID in creds.trusted_user
    assert user.AccountTypeID in creds.trusted_user_or_dev

    with db.begin():
        user.AccountTypeID = at.DEVELOPER_ID

    assert user.AccountTypeID in creds.developer
    assert user.AccountTypeID in creds.trusted_user_or_dev

    with db.begin():
        user.AccountTypeID = at.TRUSTED_USER_AND_DEV_ID

    assert user.AccountTypeID in creds.trusted_user
    assert user.AccountTypeID in creds.developer
    assert user.AccountTypeID in creds.trusted_user_or_dev

    # Some model authorization checks.
    assert user.is_elevated()
    assert user.is_trusted_user()
    assert user.is_developer()
Exemple #5
0
def main():
    args = parse_args()

    db.get_engine()
    type = db.query(AccountType,
                    AccountType.AccountType == args.type).first()
    with db.begin():
        user = db.create(User, Username=args.username,
                         Email=args.email, Passwd=args.password,
                         RealName=args.realname, IRCNick=args.ircnick,
                         PGPKey=args.pgp_key, AccountType=type)

    if args.ssh_pubkey:
        pubkey = args.ssh_pubkey.strip()

        # Remove host from the pubkey if it's there.
        pubkey = ' '.join(pubkey.split(' ')[:2])

        with db.begin():
            db.create(SSHPubKey,
                      User=user,
                      PubKey=pubkey,
                      Fingerprint=get_fingerprint(pubkey))

    print(user.json())
    return 0
Exemple #6
0
def pkgbase_disown_instance(request: Request, pkgbase: PackageBase) -> None:
    disowner = request.user
    notifs = [notify.DisownNotification(disowner.ID, pkgbase.ID)]

    is_maint = disowner == pkgbase.Maintainer
    if is_maint:
        with db.begin():
            # Comaintainer with the lowest Priority value; next-in-line.
            prio_comaint = pkgbase.comaintainers.order_by(
                PackageComaintainer.Priority.asc()
            ).first()
            if prio_comaint:
                # If there is such a comaintainer, promote them to maint.
                pkgbase.Maintainer = prio_comaint.User
                notifs.append(pkgbaseutil.remove_comaintainer(prio_comaint))
            else:
                # Otherwise, just orphan the package completely.
                pkgbase.Maintainer = None
    elif request.user.has_credential(creds.PKGBASE_DISOWN):
        # Otherwise, the request user performing this disownage is a
        # Trusted User and we treat it like a standard orphan request.
        notifs += handle_request(request, ORPHAN_ID, pkgbase)
        with db.begin():
            pkgbase.Maintainer = None
            db.delete_all(pkgbase.comaintainers)

    util.apply_all(notifs, lambda n: n.send())
Exemple #7
0
    async def authenticate(self, conn: HTTPConnection):
        unauthenticated = (None, AnonymousUser())
        sid = conn.cookies.get("AURSID")
        if not sid:
            return unauthenticated

        timeout = aurweb.config.getint("options", "login_timeout")
        remembered = ("AURREMEMBER" in conn.cookies
                      and bool(conn.cookies.get("AURREMEMBER")))
        if remembered:
            timeout = aurweb.config.getint("options",
                                           "persistent_cookie_timeout")

        # If no session with sid and a LastUpdateTS now or later exists.
        now_ts = time.utcnow()
        record = db.query(Session).filter(Session.SessionID == sid).first()
        if not record:
            return unauthenticated
        elif record.LastUpdateTS < (now_ts - timeout):
            with db.begin():
                db.delete_all([record])
            return unauthenticated

        # At this point, we cannot have an invalid user if the record
        # exists, due to ForeignKey constraints in the schema upheld
        # by mysqlclient.
        with db.begin():
            user = db.query(User).filter(User.ID == record.UsersID).first()
        user.nonce = util.make_nonce()
        user.authenticated = True

        return (AuthCredentials(["authenticated"]), user)
def test_official_provider_cs():
    """ Test case sensitivity of the database table. """
    with db.begin():
        oprovider = db.create(OfficialProvider,
                              Name="some-name",
                              Repo="some-repo",
                              Provides="some-provides")
    assert bool(oprovider.ID)

    with db.begin():
        oprovider_cs = db.create(OfficialProvider,
                                 Name="SOME-NAME",
                                 Repo="SOME-REPO",
                                 Provides="SOME-PROVIDES")
    assert bool(oprovider_cs.ID)

    assert oprovider.ID != oprovider_cs.ID

    assert oprovider.Name == "some-name"
    assert oprovider.Repo == "some-repo"
    assert oprovider.Provides == "some-provides"

    assert oprovider_cs.Name == "SOME-NAME"
    assert oprovider_cs.Repo == "SOME-REPO"
    assert oprovider_cs.Provides == "SOME-PROVIDES"
def account_type() -> AccountType:
    with db.begin():
        account_type_ = db.create(AccountType, AccountType="TestUser")

    yield account_type_

    with db.begin():
        db.delete(account_type_)
def test_request_type_creation():
    with db.begin():
        request_type = db.create(RequestType, Name="Test Request")

    assert bool(request_type.ID)
    assert request_type.Name == "Test Request"

    with db.begin():
        db.delete(request_type)
Exemple #11
0
def test_relation_type_creation():
    with db.begin():
        relation_type = db.create(RelationType, Name="test-relation")

    assert bool(relation_type.ID)
    assert relation_type.Name == "test-relation"

    with db.begin():
        db.delete(relation_type)
Exemple #12
0
def test_user_is_developer(user: User):
    with db.begin():
        user.AccountTypeID = at.DEVELOPER_ID
    assert user.is_developer() is True

    # Do it again with the combined role.
    with db.begin():
        user.AccountTypeID = at.TRUSTED_USER_AND_DEV_ID
    assert user.is_developer() is True
def test_request_type_null_name_returns_empty_string():
    with db.begin():
        request_type = db.create(RequestType)

    assert bool(request_type.ID)
    assert request_type.Name == str()

    with db.begin():
        db.delete(request_type)
Exemple #14
0
def test_create_delete():
    with db.begin():
        account_type = db.create(AccountType, AccountType="test")

    record = db.query(AccountType, AccountType.AccountType == "test").first()
    assert record is not None

    with db.begin():
        db.delete(account_type)

    record = db.query(AccountType, AccountType.AccountType == "test").first()
    assert record is None
Exemple #15
0
def test_session_cs():
    """ Test case sensitivity of the database table. """
    with db.begin():
        user2 = db.create(User, Username="******", Email="*****@*****.**",
                          ResetKey="testReset2", Passwd="testPassword",
                          AccountTypeID=USER_ID)

    with db.begin():
        session_cs = db.create(Session, User=user2, SessionID="TESTSESSION",
                               LastUpdateTS=time.utcnow())

    assert session_cs.SessionID == "TESTSESSION"
    assert session_cs.SessionID != "testSession"
Exemple #16
0
def test_merge_request(client: TestClient, user: User, tu_user: User,
                       pkgbase: PackageBase, target: PackageBase,
                       pkgreq: PackageRequest):
    """ Test merging a package with a pre - existing request. """
    with db.begin():
        pkgreq.ReqTypeID = MERGE_ID
        pkgreq.MergeBaseName = target.Name

    other_target = create_pkgbase(user, "other-target")
    other_request = create_request(MERGE_ID, user, pkgbase, "Other request.")
    other_target2 = create_pkgbase(user, "other-target2")
    other_request2 = create_request(MERGE_ID, user, pkgbase, "Other request2.")
    with db.begin():
        other_request.MergeBaseName = other_target.Name
        other_request2.MergeBaseName = other_target2.Name

    # `pkgreq`.ReqTypeID is already DELETION_ID.
    endpoint = f"/pkgbase/{pkgbase.Name}/merge"
    comments = "Test merge closure."
    data = {"into": target.Name, "comments": comments, "confirm": True}
    with client as request:
        resp = request.post(endpoint, data=data, cookies=tu_user.cookies)
    assert resp.status_code == int(HTTPStatus.SEE_OTHER)
    assert resp.headers.get("location") == f"/pkgbase/{target.Name}"

    # Ensure that `pkgreq`.ClosureComment was left alone when specified.
    assert pkgreq.ClosureComment == comments

    # We should've gotten 3 emails: an accepting and two rejections.
    assert Email.count() == 3

    # Assert specific IDs match up in the subjects.
    accepted = Email(1).parse()
    subj = r"^\[PRQ#%d\] Merge Request for [^ ]+ Accepted$" % pkgreq.ID
    assert re.match(subj, accepted.headers.get("Subject"))

    # In the accepted case, we already supplied a closure comment,
    # which stops one from being autogenerated by the algorithm.
    assert "[Autogenerated]" not in accepted.body

    # Test rejection emails, which do have autogenerated closures.
    rejected = Email(2).parse()
    subj = r"^\[PRQ#%d\] Merge Request for [^ ]+ Rejected$" % other_request.ID
    assert re.match(subj, rejected.headers.get("Subject"))
    assert "[Autogenerated]" in rejected.body

    rejected = Email(3).parse()
    subj = r"^\[PRQ#%d\] Merge Request for [^ ]+ Rejected$" % other_request2.ID
    assert re.match(subj, rejected.headers.get("Subject"))
    assert "[Autogenerated]" in rejected.body
def test_tu_voteinfo_is_running(user: User):
    ts = time.utcnow()
    with db.begin():
        tu_voteinfo = create(TUVoteInfo,
                             Agenda="Blah blah.",
                             User=user.Username,
                             Submitted=ts,
                             End=ts + 1000,
                             Quorum=0.5,
                             Submitter=user)
    assert tu_voteinfo.is_running() is True

    with db.begin():
        tu_voteinfo.End = ts - 5
    assert tu_voteinfo.is_running() is False
def test_user_account_type_relationship(account_type):
    with db.begin():
        user = db.create(User,
                         Username="******",
                         Email="*****@*****.**",
                         RealName="Test User",
                         Passwd="testPassword",
                         AccountType=account_type)

    assert user.AccountType == account_type

    # This must be db.deleted here to avoid foreign key issues when
    # deleting the temporary AccountType in the fixture.
    with db.begin():
        db.delete(user)
Exemple #19
0
def relations(user: User, packages: List[Package]) -> List[PackageRelation]:
    output = []

    with db.begin():
        rel = db.create(PackageRelation,
                        Package=packages[0],
                        RelTypeID=rt.CONFLICTS_ID,
                        RelName="chungus-conflicts")
        output.append(rel)

        rel = db.create(PackageRelation,
                        Package=packages[1],
                        RelTypeID=rt.CONFLICTS_ID,
                        RelName="chungy-conflicts")
        output.append(rel)

        rel = db.create(PackageRelation,
                        Package=packages[0],
                        RelTypeID=rt.PROVIDES_ID,
                        RelName="chungus-provides",
                        RelCondition="<=200")
        output.append(rel)

        rel = db.create(PackageRelation,
                        Package=packages[0],
                        RelTypeID=rt.REPLACES_ID,
                        RelName="chungus-replaces",
                        RelCondition="<=200")
        output.append(rel)

    # Finally, yield the packages.
    yield output
Exemple #20
0
def simple(U: str = str(),
           E: str = str(),
           H: bool = False,
           BE: str = str(),
           R: str = str(),
           HP: str = str(),
           I: str = str(),
           K: str = str(),
           J: bool = False,
           CN: bool = False,
           UN: bool = False,
           ON: bool = False,
           S: bool = False,
           user: models.User = None,
           **kwargs) -> None:
    now = time.utcnow()
    with db.begin():
        user.Username = U or user.Username
        user.Email = E or user.Email
        user.HideEmail = strtobool(H)
        user.BackupEmail = user.BackupEmail if BE is None else BE
        user.RealName = user.RealName if R is None else R
        user.Homepage = user.Homepage if HP is None else HP
        user.IRCNick = user.IRCNick if I is None else I
        user.PGPKey = user.PGPKey if K is None else K
        user.Suspended = strtobool(S)
        user.InactivityTS = now * int(strtobool(J))
        user.CommentNotify = strtobool(CN)
        user.UpdateNotify = strtobool(UN)
        user.OwnershipNotify = strtobool(ON)
Exemple #21
0
def test_package_dependencies(user: User, package: Package):
    with db.begin():
        pkgdep = db.create(PackageDependency,
                           Package=package,
                           DepTypeID=DEPENDS_ID,
                           DepName="test-dep")
    assert pkgdep.DepName == "test-dep"
    assert pkgdep.Package == package
    assert pkgdep in package.package_dependencies
    assert not pkgdep.is_package()

    with db.begin():
        base = db.create(PackageBase, Name=pkgdep.DepName, Maintainer=user)
        db.create(Package, PackageBase=base, Name=pkgdep.DepName)

    assert pkgdep.is_package()
def test_package_source(package: Package):
    with db.begin():
        pkgsource = db.create(PackageSource, Package=package)
    assert pkgsource.Package == package
    # By default, PackageSources.Source assigns the string '/dev/null'.
    assert pkgsource.Source == "/dev/null"
    assert pkgsource.SourceArch is None
Exemple #23
0
def test_homepage_dashboard(redis, packages, user):
    # Create Comaintainer records for all of the packages.
    with db.begin():
        for pkg in packages:
            db.create(PackageComaintainer,
                      PackageBase=pkg.PackageBase,
                      User=user,
                      Priority=1)

    cookies = {"AURSID": user.login(Request(), "testPassword")}
    with client as request:
        response = request.get("/", cookies=cookies)
    assert response.status_code == int(HTTPStatus.OK)

    root = parse_root(response.text)

    # Assert some expectations that we end up getting all fifty
    # packages in the "My Packages" table.
    expectations = [f"pkg_{i}" for i in range(50 - 1, 0, -1)]
    my_packages = root.xpath('//table[@id="my-packages"]/tbody/tr')
    for i, expected in enumerate(expectations):
        name, version, votes, pop, voted, notify, desc, maint \
            = my_packages[i].xpath('./td')
        assert name.xpath('./a').pop(0).text.strip() == expected

    # Do the same for the Comaintained Packages table.
    my_packages = root.xpath('//table[@id="comaintained-packages"]/tbody/tr')
    for i, expected in enumerate(expectations):
        name, version, votes, pop, voted, notify, desc, maint \
            = my_packages[i].xpath('./td')
        assert name.xpath('./a').pop(0).text.strip() == expected
def test_tu_proposal_vote_already_voted(client, proposal):
    tu_user, user, voteinfo = proposal

    with db.begin():
        db.create(TUVote, VoteInfo=voteinfo, User=tu_user)
        voteinfo.Yes += 1
        voteinfo.ActiveTUs += 1

    cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
    with client as request:
        data = {"decision": "Yes"}
        response = request.post(f"/tu/{voteinfo.ID}",
                                cookies=cookies,
                                data=data,
                                allow_redirects=False)
    assert response.status_code == int(HTTPStatus.BAD_REQUEST)

    root = parse_root(response.text)
    status = root.xpath('//span[contains(@class, "status")]/text()')[0]
    assert status == "You've already voted for this proposal."

    with client as request:
        data = {"decision": "Yes"}
        response = request.get(f"/tu/{voteinfo.ID}",
                               cookies=cookies,
                               data=data,
                               allow_redirects=False)
    assert response.status_code == int(HTTPStatus.OK)

    root = parse_root(response.text)
    status = root.xpath('//span[contains(@class, "status")]/text()')[0]
    assert status == "You've already voted for this proposal."
def test_tu_proposal_vote_cant_self_vote(client, proposal):
    tu_user, user, voteinfo = proposal

    # Update voteinfo.User.
    with db.begin():
        voteinfo.User = tu_user.Username

    cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
    with client as request:
        data = {"decision": "Yes"}
        response = request.post(f"/tu/{voteinfo.ID}",
                                cookies=cookies,
                                data=data,
                                allow_redirects=False)
    assert response.status_code == int(HTTPStatus.BAD_REQUEST)

    root = parse_root(response.text)
    status = root.xpath('//span[contains(@class, "status")]/text()')[0]
    assert status == "You cannot vote in an proposal about you."

    with client as request:
        data = {"decision": "Yes"}
        response = request.get(f"/tu/{voteinfo.ID}",
                               cookies=cookies,
                               data=data,
                               allow_redirects=False)
    assert response.status_code == int(HTTPStatus.OK)

    root = parse_root(response.text)
    status = root.xpath('//span[contains(@class, "status")]/text()')[0]
    assert status == "You cannot vote in an proposal about you."
def test_tu_proposal_vote_unauthorized(client: TestClient,
                                       proposal: Tuple[User, User,
                                                       TUVoteInfo]):
    tu_user, user, voteinfo = proposal

    with db.begin():
        tu_user.AccountTypeID = DEVELOPER_ID

    cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
    with client as request:
        data = {"decision": "Yes"}
        response = request.post(f"/tu/{voteinfo.ID}",
                                cookies=cookies,
                                data=data,
                                allow_redirects=False)
    assert response.status_code == int(HTTPStatus.UNAUTHORIZED)

    root = parse_root(response.text)
    status = root.xpath('//span[contains(@class, "status")]/text()')[0]
    assert status == "Only Trusted Users are allowed to vote."

    with client as request:
        data = {"decision": "Yes"}
        response = request.get(f"/tu/{voteinfo.ID}",
                               cookies=cookies,
                               data=data,
                               allow_redirects=False)
    assert response.status_code == int(HTTPStatus.OK)

    root = parse_root(response.text)
    status = root.xpath('//span[contains(@class, "status")]/text()')[0]
    assert status == "Only Trusted Users are allowed to vote."
Exemple #27
0
def test_rpc_msearch(client: TestClient, user: User, packages: List[Package]):
    params = {"v": 5, "type": "msearch", "arg": user.Username}
    with client as request:
        response = request.get("/rpc", params=params)
    data = response.json()

    # user1 maintains 4 packages; assert that we got them all.
    assert data.get("resultcount") == 4
    names = list(sorted(r.get("Name") for r in data.get("results")))
    expected_results = [
        "big-chungus", "chungy-chungus", "gluggly-chungus", "other-pkg"
    ]
    assert names == expected_results

    # Search for a non-existent maintainer, giving us zero packages.
    params["arg"] = "blah-blah"
    response = request.get("/rpc", params=params)
    data = response.json()
    assert data.get("resultcount") == 0

    with db.begin():
        packages[0].PackageBase.Maintainer = None

    # A missing arg still succeeds, but it returns all orphans.
    # Just verify that we receive no error and the orphaned result.
    params.pop("arg")
    response = request.get("/rpc", params=params)
    data = response.json()
    assert data.get("resultcount") == 1
    result = data.get("results")[0]
    assert result.get("Name") == "big-chungus"
Exemple #28
0
def test_rpc_too_many_info_results(client: TestClient,
                                   packages: List[Package]):
    # Make many of these packages depend and rely on each other.
    # This way, we can test to see that the exceeded limit stays true
    # regardless of the number of related records.
    with db.begin():
        for i in range(len(packages) - 1):
            db.create(PackageDependency,
                      DepTypeID=DEPENDS_ID,
                      Package=packages[i],
                      DepName=packages[i + 1].Name)
            db.create(PackageRelation,
                      RelTypeID=PROVIDES_ID,
                      Package=packages[i],
                      RelName=packages[i + 1].Name)

    config_getint = config.getint

    def mock_config(section: str, key: str):
        if key == "max_rpc_results":
            return 1
        return config_getint(section, key)

    params = {"v": 5, "type": "info", "arg[]": [p.Name for p in packages]}
    with mock.patch("aurweb.config.getint", side_effect=mock_config):
        with client as request:
            resp = request.get("/rpc", params=params)
    assert resp.json().get("error") == "Too many package results."
Exemple #29
0
def test_homepage_dashboard_flagged(user: User, user2: User, package: Package):
    pkgbase = package.PackageBase

    now = time.utcnow()
    with db.begin():
        db.create(PackageComaintainer,
                  User=user2,
                  PackageBase=pkgbase,
                  Priority=1)
        pkgbase.OutOfDateTS = now - 5
        pkgbase.Flagger = user

    # Test that a comaintainer viewing the dashboard shows them their
    # flagged co-maintained packages.
    comaint_cookies = {"AURSID": user2.login(Request(), "testPassword")}
    with client as request:
        resp = request.get("/", cookies=comaint_cookies)
    assert resp.status_code == int(HTTPStatus.OK)

    root = parse_root(resp.text)
    flagged = root.xpath('//table[@id="flagged-packages"]//tr/td/a')[0]
    assert flagged.text.strip() == package.Name

    # Test that a maintainer viewing the dashboard shows them their
    # flagged maintained packages.
    cookies = {"AURSID": user.login(Request(), "testPassword")}
    with client as request:
        resp = request.get("/", cookies=cookies)
    assert resp.status_code == int(HTTPStatus.OK)

    root = parse_root(resp.text)
    flagged = root.xpath('//table[@id="flagged-packages"]//tr/td/a')[0]
    assert flagged.text.strip() == package.Name
Exemple #30
0
async def request_close_post(request: Request,
                             id: int,
                             comments: str = Form(default=str())):
    pkgreq = get_pkgreq_by_id(id)

    # `pkgreq`.User can close their own request.
    approved = [pkgreq.User]
    if not request.user.has_credential(creds.PKGREQ_CLOSE, approved=approved):
        # Request user doesn't have permission here: redirect to '/'.
        return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)

    context = make_context(request, "Close Request")
    context["pkgreq"] = pkgreq

    now = time.utcnow()
    with db.begin():
        pkgreq.Closer = request.user
        pkgreq.ClosureComment = comments
        pkgreq.ClosedTS = now
        pkgreq.Status = REJECTED_ID

    notify_ = notify.RequestCloseNotification(request.user.ID, pkgreq.ID,
                                              pkgreq.status_display())
    notify_.send()

    return RedirectResponse("/requests", status_code=HTTPStatus.SEE_OTHER)