Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • wackbyte/aurweb
  • aliu/aurweb
  • morganamilo/aurweb
  • tex/aurweb
  • abitrolly/aurweb
  • muflone/aurweb
  • anthraxx/aurweb
  • jafari/aurweb
  • levitating/aurweb
  • freso/aurweb
  • okabe/aurweb
  • rafaelff/aurweb
  • zoorat/aurweb
  • auerhuhn/aurweb
  • nils/aurweb
  • antiz/aurweb
  • henry-zhr/aurweb
  • segaja/aurweb
  • som015/aurweb
  • gromit/aurweb
  • belongingtome47/aurweb
  • moson/aurweb
  • steppaa23/aurweb
  • bittin/aurweb
  • jkhsjdhjs/aurweb
  • whynothugo/aurweb
  • matt/aurweb
  • fosskers/aurweb
  • awalgarg/aurweb
  • robertoszek/aurweb
  • ainola/aurweb
  • fluix/aurweb
  • hwittenborn/aurweb
  • jocke-l/aurweb
  • eschwartz/aurweb
  • mackilanu/aurweb
  • artafinde/aurweb
  • klausenbusk/aurweb
  • felixonmars/aurweb
  • kevr/aurweb
  • hashworks/aurweb
  • freswa/aurweb
  • lahwaacz/aurweb
  • jelle/aurweb
  • ffy00/aurweb
  • archlinux/aurweb
46 results
Show changes
Showing
with 1191 additions and 455 deletions
......@@ -9,12 +9,12 @@ import aurweb.db
def format_command(env_vars, command, ssh_opts, ssh_key):
environment = ''
environment = ""
for key, var in env_vars.items():
environment += '{}={} '.format(key, shlex.quote(var))
environment += "{}={} ".format(key, shlex.quote(var))
command = shlex.quote(command)
command = '{}{}'.format(environment, command)
command = "{}{}".format(environment, command)
# The command is being substituted into an authorized_keys line below,
# so we need to escape the double quotes.
......@@ -24,10 +24,10 @@ def format_command(env_vars, command, ssh_opts, ssh_key):
def main():
valid_keytypes = aurweb.config.get('auth', 'valid-keytypes').split()
username_regex = aurweb.config.get('auth', 'username-regex')
git_serve_cmd = aurweb.config.get('auth', 'git-serve-cmd')
ssh_opts = aurweb.config.get('auth', 'ssh-options')
valid_keytypes = aurweb.config.get("auth", "valid-keytypes").split()
username_regex = aurweb.config.get("auth", "username-regex")
git_serve_cmd = aurweb.config.get("auth", "git-serve-cmd")
ssh_opts = aurweb.config.get("auth", "ssh-options")
keytype = sys.argv[1]
keytext = sys.argv[2]
......@@ -36,11 +36,13 @@ def main():
conn = aurweb.db.Connection()
cur = conn.execute("SELECT Users.Username, Users.AccountTypeID FROM Users "
"INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID "
"WHERE SSHPubKeys.PubKey = ? AND Users.Suspended = 0 "
"AND NOT Users.Passwd = ''",
(keytype + " " + keytext,))
cur = conn.execute(
"SELECT Users.Username, Users.AccountTypeID FROM Users "
"INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID "
"WHERE SSHPubKeys.PubKey = ? AND Users.Suspended = 0 "
"AND NOT Users.Passwd = ''",
(keytype + " " + keytext,),
)
row = cur.fetchone()
if not row or cur.fetchone():
......@@ -51,13 +53,13 @@ def main():
exit(1)
env_vars = {
'AUR_USER': user,
'AUR_PRIVILEGED': '1' if account_type > 1 else '0',
"AUR_USER": user,
"AUR_PRIVILEGED": "1" if account_type > 1 else "0",
}
key = keytype + ' ' + keytext
key = keytype + " " + keytext
print(format_command(env_vars, git_serve_cmd, ssh_opts, key))
if __name__ == '__main__':
if __name__ == "__main__":
main()
......@@ -11,16 +11,16 @@ import aurweb.config
import aurweb.db
import aurweb.exceptions
notify_cmd = aurweb.config.get('notifications', 'notify-cmd')
notify_cmd = aurweb.config.get("notifications", "notify-cmd")
repo_path = aurweb.config.get('serve', 'repo-path')
repo_regex = aurweb.config.get('serve', 'repo-regex')
git_shell_cmd = aurweb.config.get('serve', 'git-shell-cmd')
git_update_cmd = aurweb.config.get('serve', 'git-update-cmd')
ssh_cmdline = aurweb.config.get('serve', 'ssh-cmdline')
repo_path = aurweb.config.get("serve", "repo-path")
repo_regex = aurweb.config.get("serve", "repo-regex")
git_shell_cmd = aurweb.config.get("serve", "git-shell-cmd")
git_update_cmd = aurweb.config.get("serve", "git-update-cmd")
ssh_cmdline = aurweb.config.get("serve", "ssh-cmdline")
enable_maintenance = aurweb.config.getboolean('options', 'enable-maintenance')
maintenance_exc = aurweb.config.get('options', 'maintenance-exceptions').split()
enable_maintenance = aurweb.config.getboolean("options", "enable-maintenance")
maintenance_exc = aurweb.config.get("options", "maintenance-exceptions").split()
def pkgbase_from_name(pkgbase):
......@@ -43,14 +43,16 @@ def list_repos(user):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
cur = conn.execute("SELECT Name, PackagerUID FROM PackageBases " +
"WHERE MaintainerUID = ?", [userid])
cur = conn.execute(
"SELECT Name, PackagerUID FROM PackageBases " + "WHERE MaintainerUID = ?",
[userid],
)
for row in cur:
print((' ' if row[1] else '*') + row[0])
print((" " if row[1] else "*") + row[0])
conn.close()
def create_pkgbase(pkgbase, user):
def validate_pkgbase(pkgbase, user):
if not re.match(repo_regex, pkgbase):
raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase)
if pkgbase_exists(pkgbase):
......@@ -60,23 +62,12 @@ def create_pkgbase(pkgbase, user):
cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
userid = cur.fetchone()[0]
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
now = int(time.time())
cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " +
"ModifiedTS, SubmitterUID, MaintainerUID, " +
"FlaggerComment) VALUES (?, ?, ?, ?, ?, '')",
[pkgbase, now, now, userid, userid])
pkgbase_id = cur.lastrowid
cur = conn.execute("INSERT INTO PackageNotifications " +
"(PackageBaseID, UserID) VALUES (?, ?)",
[pkgbase_id, userid])
conn.commit()
conn.close()
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
def pkgbase_adopt(pkgbase, user, privileged):
pkgbase_id = pkgbase_from_name(pkgbase)
......@@ -85,8 +76,10 @@ def pkgbase_adopt(pkgbase, user, privileged):
conn = aurweb.db.Connection()
cur = conn.execute("SELECT ID FROM PackageBases WHERE ID = ? AND " +
"MaintainerUID IS NULL", [pkgbase_id])
cur = conn.execute(
"SELECT ID FROM PackageBases WHERE ID = ? AND " + "MaintainerUID IS NULL",
[pkgbase_id],
)
if not privileged and not cur.fetchone():
raise aurweb.exceptions.PermissionDeniedException(user)
......@@ -95,19 +88,25 @@ def pkgbase_adopt(pkgbase, user, privileged):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " +
"WHERE ID = ?", [userid, pkgbase_id])
cur = conn.execute(
"UPDATE PackageBases SET MaintainerUID = ? " + "WHERE ID = ?",
[userid, pkgbase_id],
)
cur = conn.execute("SELECT COUNT(*) FROM PackageNotifications WHERE " +
"PackageBaseID = ? AND UserID = ?",
[pkgbase_id, userid])
cur = conn.execute(
"SELECT COUNT(*) FROM PackageNotifications WHERE "
+ "PackageBaseID = ? AND UserID = ?",
[pkgbase_id, userid],
)
if cur.fetchone()[0] == 0:
cur = conn.execute("INSERT INTO PackageNotifications " +
"(PackageBaseID, UserID) VALUES (?, ?)",
[pkgbase_id, userid])
cur = conn.execute(
"INSERT INTO PackageNotifications "
+ "(PackageBaseID, UserID) VALUES (?, ?)",
[pkgbase_id, userid],
)
conn.commit()
subprocess.Popen((notify_cmd, 'adopt', str(userid), str(pkgbase_id)))
subprocess.Popen((notify_cmd, "adopt", str(userid), str(pkgbase_id)))
conn.close()
......@@ -115,13 +114,16 @@ def pkgbase_adopt(pkgbase, user, privileged):
def pkgbase_get_comaintainers(pkgbase):
conn = aurweb.db.Connection()
cur = conn.execute("SELECT UserName FROM PackageComaintainers " +
"INNER JOIN Users " +
"ON Users.ID = PackageComaintainers.UsersID " +
"INNER JOIN PackageBases " +
"ON PackageBases.ID = PackageComaintainers.PackageBaseID " +
"WHERE PackageBases.Name = ? " +
"ORDER BY Priority ASC", [pkgbase])
cur = conn.execute(
"SELECT UserName FROM PackageComaintainers "
+ "INNER JOIN Users "
+ "ON Users.ID = PackageComaintainers.UsersID "
+ "INNER JOIN PackageBases "
+ "ON PackageBases.ID = PackageComaintainers.PackageBaseID "
+ "WHERE PackageBases.Name = ? "
+ "ORDER BY Priority ASC",
[pkgbase],
)
return [row[0] for row in cur.fetchall()]
......@@ -140,8 +142,7 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
uids_old = set()
for olduser in userlist_old:
cur = conn.execute("SELECT ID FROM Users WHERE Username = ?",
[olduser])
cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [olduser])
userid = cur.fetchone()[0]
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
......@@ -149,8 +150,7 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
uids_new = set()
for newuser in userlist:
cur = conn.execute("SELECT ID FROM Users WHERE Username = ?",
[newuser])
cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [newuser])
userid = cur.fetchone()[0]
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
......@@ -162,24 +162,33 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
i = 1
for userid in uids_new:
if userid in uids_add:
cur = conn.execute("INSERT INTO PackageComaintainers " +
"(PackageBaseID, UsersID, Priority) " +
"VALUES (?, ?, ?)", [pkgbase_id, userid, i])
subprocess.Popen((notify_cmd, 'comaintainer-add', str(userid),
str(pkgbase_id)))
cur = conn.execute(
"INSERT INTO PackageComaintainers "
+ "(PackageBaseID, UsersID, Priority) "
+ "VALUES (?, ?, ?)",
[pkgbase_id, userid, i],
)
subprocess.Popen(
(notify_cmd, "comaintainer-add", str(userid), str(pkgbase_id))
)
else:
cur = conn.execute("UPDATE PackageComaintainers " +
"SET Priority = ? " +
"WHERE PackageBaseID = ? AND UsersID = ?",
[i, pkgbase_id, userid])
cur = conn.execute(
"UPDATE PackageComaintainers "
+ "SET Priority = ? "
+ "WHERE PackageBaseID = ? AND UsersID = ?",
[i, pkgbase_id, userid],
)
i += 1
for userid in uids_rem:
cur = conn.execute("DELETE FROM PackageComaintainers " +
"WHERE PackageBaseID = ? AND UsersID = ?",
[pkgbase_id, userid])
subprocess.Popen((notify_cmd, 'comaintainer-remove',
str(userid), str(pkgbase_id)))
cur = conn.execute(
"DELETE FROM PackageComaintainers "
+ "WHERE PackageBaseID = ? AND UsersID = ?",
[pkgbase_id, userid],
)
subprocess.Popen(
(notify_cmd, "comaintainer-remove", str(userid), str(pkgbase_id))
)
conn.commit()
conn.close()
......@@ -188,18 +197,21 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
def pkgreq_by_pkgbase(pkgbase_id, reqtype):
conn = aurweb.db.Connection()
cur = conn.execute("SELECT PackageRequests.ID FROM PackageRequests " +
"INNER JOIN RequestTypes ON " +
"RequestTypes.ID = PackageRequests.ReqTypeID " +
"WHERE PackageRequests.Status = 0 " +
"AND PackageRequests.PackageBaseID = ? " +
"AND RequestTypes.Name = ?", [pkgbase_id, reqtype])
cur = conn.execute(
"SELECT PackageRequests.ID FROM PackageRequests "
+ "INNER JOIN RequestTypes ON "
+ "RequestTypes.ID = PackageRequests.ReqTypeID "
+ "WHERE PackageRequests.Status = 0 "
+ "AND PackageRequests.PackageBaseID = ? "
+ "AND RequestTypes.Name = ?",
[pkgbase_id, reqtype],
)
return [row[0] for row in cur.fetchall()]
def pkgreq_close(reqid, user, reason, comments, autoclose=False):
statusmap = {'accepted': 2, 'rejected': 3}
statusmap = {"accepted": 2, "rejected": 3}
if reason not in statusmap:
raise aurweb.exceptions.InvalidReasonException(reason)
status = statusmap[reason]
......@@ -215,16 +227,20 @@ def pkgreq_close(reqid, user, reason, comments, autoclose=False):
raise aurweb.exceptions.InvalidUserException(user)
now = int(time.time())
conn.execute("UPDATE PackageRequests SET Status = ?, ClosedTS = ?, " +
"ClosedUID = ?, ClosureComment = ? " +
"WHERE ID = ?", [status, now, userid, comments, reqid])
conn.execute(
"UPDATE PackageRequests SET Status = ?, ClosedTS = ?, "
+ "ClosedUID = ?, ClosureComment = ? "
+ "WHERE ID = ?",
[status, now, userid, comments, reqid],
)
conn.commit()
conn.close()
if not userid:
userid = 0
subprocess.Popen((notify_cmd, 'request-close', str(userid), str(reqid),
reason)).wait()
subprocess.Popen(
(notify_cmd, "request-close", str(userid), str(reqid), reason)
).wait()
def pkgbase_disown(pkgbase, user, privileged):
......@@ -239,9 +255,9 @@ def pkgbase_disown(pkgbase, user, privileged):
# TODO: Support disowning package bases via package request.
# Scan through pending orphan requests and close them.
comment = 'The user {:s} disowned the package.'.format(user)
for reqid in pkgreq_by_pkgbase(pkgbase_id, 'orphan'):
pkgreq_close(reqid, user, 'accepted', comment, True)
comment = "The user {:s} disowned the package.".format(user)
for reqid in pkgreq_by_pkgbase(pkgbase_id, "orphan"):
pkgreq_close(reqid, user, "accepted", comment, True)
comaintainers = []
new_maintainer_userid = None
......@@ -249,19 +265,22 @@ def pkgbase_disown(pkgbase, user, privileged):
conn = aurweb.db.Connection()
# Make the first co-maintainer the new maintainer, unless the action was
# enforced by a Trusted User.
# enforced by a Package Maintainer.
if initialized_by_owner:
comaintainers = pkgbase_get_comaintainers(pkgbase)
if len(comaintainers) > 0:
new_maintainer = comaintainers[0]
cur = conn.execute("SELECT ID FROM Users WHERE Username = ?",
[new_maintainer])
cur = conn.execute(
"SELECT ID FROM Users WHERE Username = ?", [new_maintainer]
)
new_maintainer_userid = cur.fetchone()[0]
comaintainers.remove(new_maintainer)
pkgbase_set_comaintainers(pkgbase, comaintainers, user, privileged)
cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " +
"WHERE ID = ?", [new_maintainer_userid, pkgbase_id])
cur = conn.execute(
"UPDATE PackageBases SET MaintainerUID = ? " + "WHERE ID = ?",
[new_maintainer_userid, pkgbase_id],
)
conn.commit()
......@@ -270,7 +289,7 @@ def pkgbase_disown(pkgbase, user, privileged):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
subprocess.Popen((notify_cmd, 'disown', str(userid), str(pkgbase_id)))
subprocess.Popen((notify_cmd, "disown", str(userid), str(pkgbase_id)))
conn.close()
......@@ -290,14 +309,16 @@ def pkgbase_flag(pkgbase, user, comment):
raise aurweb.exceptions.InvalidUserException(user)
now = int(time.time())
conn.execute("UPDATE PackageBases SET " +
"OutOfDateTS = ?, FlaggerUID = ?, FlaggerComment = ? " +
"WHERE ID = ? AND OutOfDateTS IS NULL",
[now, userid, comment, pkgbase_id])
conn.execute(
"UPDATE PackageBases SET "
+ "OutOfDateTS = ?, FlaggerUID = ?, FlaggerComment = ? "
+ "WHERE ID = ? AND OutOfDateTS IS NULL",
[now, userid, comment, pkgbase_id],
)
conn.commit()
subprocess.Popen((notify_cmd, 'flag', str(userid), str(pkgbase_id)))
subprocess.Popen((notify_cmd, "flag", str(userid), str(pkgbase_id)))
def pkgbase_unflag(pkgbase, user):
......@@ -313,12 +334,15 @@ def pkgbase_unflag(pkgbase, user):
raise aurweb.exceptions.InvalidUserException(user)
if user in pkgbase_get_comaintainers(pkgbase):
conn.execute("UPDATE PackageBases SET OutOfDateTS = NULL " +
"WHERE ID = ?", [pkgbase_id])
conn.execute(
"UPDATE PackageBases SET OutOfDateTS = NULL " + "WHERE ID = ?", [pkgbase_id]
)
else:
conn.execute("UPDATE PackageBases SET OutOfDateTS = NULL " +
"WHERE ID = ? AND (MaintainerUID = ? OR FlaggerUID = ?)",
[pkgbase_id, userid, userid])
conn.execute(
"UPDATE PackageBases SET OutOfDateTS = NULL "
+ "WHERE ID = ? AND (MaintainerUID = ? OR FlaggerUID = ?)",
[pkgbase_id, userid, userid],
)
conn.commit()
......@@ -335,17 +359,24 @@ def pkgbase_vote(pkgbase, user):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
cur = conn.execute("SELECT COUNT(*) FROM PackageVotes " +
"WHERE UsersID = ? AND PackageBaseID = ?",
[userid, pkgbase_id])
cur = conn.execute(
"SELECT COUNT(*) FROM PackageVotes "
+ "WHERE UsersID = ? AND PackageBaseID = ?",
[userid, pkgbase_id],
)
if cur.fetchone()[0] > 0:
raise aurweb.exceptions.AlreadyVotedException(pkgbase)
now = int(time.time())
conn.execute("INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) " +
"VALUES (?, ?, ?)", [userid, pkgbase_id, now])
conn.execute("UPDATE PackageBases SET NumVotes = NumVotes + 1 " +
"WHERE ID = ?", [pkgbase_id])
conn.execute(
"INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) "
+ "VALUES (?, ?, ?)",
[userid, pkgbase_id, now],
)
conn.execute(
"UPDATE PackageBases SET NumVotes = NumVotes + 1 " + "WHERE ID = ?",
[pkgbase_id],
)
conn.commit()
......@@ -361,16 +392,22 @@ def pkgbase_unvote(pkgbase, user):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
cur = conn.execute("SELECT COUNT(*) FROM PackageVotes " +
"WHERE UsersID = ? AND PackageBaseID = ?",
[userid, pkgbase_id])
cur = conn.execute(
"SELECT COUNT(*) FROM PackageVotes "
+ "WHERE UsersID = ? AND PackageBaseID = ?",
[userid, pkgbase_id],
)
if cur.fetchone()[0] == 0:
raise aurweb.exceptions.NotVotedException(pkgbase)
conn.execute("DELETE FROM PackageVotes WHERE UsersID = ? AND " +
"PackageBaseID = ?", [userid, pkgbase_id])
conn.execute("UPDATE PackageBases SET NumVotes = NumVotes - 1 " +
"WHERE ID = ?", [pkgbase_id])
conn.execute(
"DELETE FROM PackageVotes WHERE UsersID = ? AND " + "PackageBaseID = ?",
[userid, pkgbase_id],
)
conn.execute(
"UPDATE PackageBases SET NumVotes = NumVotes - 1 " + "WHERE ID = ?",
[pkgbase_id],
)
conn.commit()
......@@ -381,11 +418,12 @@ def pkgbase_set_keywords(pkgbase, keywords):
conn = aurweb.db.Connection()
conn.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = ?",
[pkgbase_id])
conn.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = ?", [pkgbase_id])
for keyword in keywords:
conn.execute("INSERT INTO PackageKeywords (PackageBaseID, Keyword) " +
"VALUES (?, ?)", [pkgbase_id, keyword])
conn.execute(
"INSERT INTO PackageKeywords (PackageBaseID, Keyword) " + "VALUES (?, ?)",
[pkgbase_id, keyword],
)
conn.commit()
conn.close()
......@@ -394,24 +432,30 @@ def pkgbase_set_keywords(pkgbase, keywords):
def pkgbase_has_write_access(pkgbase, user):
conn = aurweb.db.Connection()
cur = conn.execute("SELECT COUNT(*) FROM PackageBases " +
"LEFT JOIN PackageComaintainers " +
"ON PackageComaintainers.PackageBaseID = PackageBases.ID " +
"INNER JOIN Users " +
"ON Users.ID = PackageBases.MaintainerUID " +
"OR PackageBases.MaintainerUID IS NULL " +
"OR Users.ID = PackageComaintainers.UsersID " +
"WHERE Name = ? AND Username = ?", [pkgbase, user])
cur = conn.execute(
"SELECT COUNT(*) FROM PackageBases "
+ "LEFT JOIN PackageComaintainers "
+ "ON PackageComaintainers.PackageBaseID = PackageBases.ID "
+ "INNER JOIN Users "
+ "ON Users.ID = PackageBases.MaintainerUID "
+ "OR PackageBases.MaintainerUID IS NULL "
+ "OR Users.ID = PackageComaintainers.UsersID "
+ "WHERE Name = ? AND Username = ?",
[pkgbase, user],
)
return cur.fetchone()[0] > 0
def pkgbase_has_full_access(pkgbase, user):
conn = aurweb.db.Connection()
cur = conn.execute("SELECT COUNT(*) FROM PackageBases " +
"INNER JOIN Users " +
"ON Users.ID = PackageBases.MaintainerUID " +
"WHERE Name = ? AND Username = ?", [pkgbase, user])
cur = conn.execute(
"SELECT COUNT(*) FROM PackageBases "
+ "INNER JOIN Users "
+ "ON Users.ID = PackageBases.MaintainerUID "
+ "WHERE Name = ? AND Username = ?",
[pkgbase, user],
)
return cur.fetchone()[0] > 0
......@@ -419,9 +463,11 @@ def log_ssh_login(user, remote_addr):
conn = aurweb.db.Connection()
now = int(time.time())
conn.execute("UPDATE Users SET LastSSHLogin = ?, " +
"LastSSHLoginIPAddress = ? WHERE Username = ?",
[now, remote_addr, user])
conn.execute(
"UPDATE Users SET LastSSHLogin = ?, "
+ "LastSSHLoginIPAddress = ? WHERE Username = ?",
[now, remote_addr, user],
)
conn.commit()
conn.close()
......@@ -430,8 +476,7 @@ def log_ssh_login(user, remote_addr):
def bans_match(remote_addr):
conn = aurweb.db.Connection()
cur = conn.execute("SELECT COUNT(*) FROM Bans WHERE IPAddress = ?",
[remote_addr])
cur = conn.execute("SELECT COUNT(*) FROM Bans WHERE IPAddress = ?", [remote_addr])
return cur.fetchone()[0] > 0
......@@ -458,13 +503,13 @@ def usage(cmds):
def checkarg_atleast(cmdargv, *argdesc):
if len(cmdargv) - 1 < len(argdesc):
msg = 'missing {:s}'.format(argdesc[len(cmdargv) - 1])
msg = "missing {:s}".format(argdesc[len(cmdargv) - 1])
raise aurweb.exceptions.InvalidArgumentsException(msg)
def checkarg_atmost(cmdargv, *argdesc):
if len(cmdargv) - 1 > len(argdesc):
raise aurweb.exceptions.InvalidArgumentsException('too many arguments')
raise aurweb.exceptions.InvalidArgumentsException("too many arguments")
def checkarg(cmdargv, *argdesc):
......@@ -480,23 +525,23 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901
raise aurweb.exceptions.BannedException
log_ssh_login(user, remote_addr)
if action == 'git' and cmdargv[1] in ('upload-pack', 'receive-pack'):
action = action + '-' + cmdargv[1]
if action == "git" and cmdargv[1] in ("upload-pack", "receive-pack"):
action = action + "-" + cmdargv[1]
del cmdargv[1]
if action == 'git-upload-pack' or action == 'git-receive-pack':
checkarg(cmdargv, 'path')
if action == "git-upload-pack" or action == "git-receive-pack":
checkarg(cmdargv, "path")
path = cmdargv[1].rstrip('/')
if not path.startswith('/'):
path = '/' + path
if not path.endswith('.git'):
path = path + '.git'
path = cmdargv[1].rstrip("/")
if not path.startswith("/"):
path = "/" + path
if not path.endswith(".git"):
path = path + ".git"
pkgbase = path[1:-4]
if not re.match(repo_regex, pkgbase):
raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase)
if action == 'git-receive-pack' and pkgbase_exists(pkgbase):
if action == "git-receive-pack" and pkgbase_exists(pkgbase):
if not privileged and not pkgbase_has_write_access(pkgbase, user):
raise aurweb.exceptions.PermissionDeniedException(user)
......@@ -507,65 +552,60 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901
os.environ["AUR_PKGBASE"] = pkgbase
os.environ["GIT_NAMESPACE"] = pkgbase
cmd = action + " '" + repo_path + "'"
os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd)
elif action == 'set-keywords':
checkarg_atleast(cmdargv, 'repository name')
os.execl(git_shell_cmd, git_shell_cmd, "-c", cmd)
elif action == "set-keywords":
checkarg_atleast(cmdargv, "repository name")
pkgbase_set_keywords(cmdargv[1], cmdargv[2:])
elif action == 'list-repos':
elif action == "list-repos":
checkarg(cmdargv)
list_repos(user)
elif action == 'setup-repo':
checkarg(cmdargv, 'repository name')
warn('{:s} is deprecated. '
'Use `git push` to create new repositories.'.format(action))
create_pkgbase(cmdargv[1], user)
elif action == 'restore':
checkarg(cmdargv, 'repository name')
elif action == "restore":
checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
create_pkgbase(pkgbase, user)
validate_pkgbase(pkgbase, user)
os.environ["AUR_USER"] = user
os.environ["AUR_PKGBASE"] = pkgbase
os.execl(git_update_cmd, git_update_cmd, 'restore')
elif action == 'adopt':
checkarg(cmdargv, 'repository name')
os.execl(git_update_cmd, git_update_cmd, "restore")
elif action == "adopt":
checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_adopt(pkgbase, user, privileged)
elif action == 'disown':
checkarg(cmdargv, 'repository name')
elif action == "disown":
checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_disown(pkgbase, user, privileged)
elif action == 'flag':
checkarg(cmdargv, 'repository name', 'comment')
elif action == "flag":
checkarg(cmdargv, "repository name", "comment")
pkgbase = cmdargv[1]
comment = cmdargv[2]
pkgbase_flag(pkgbase, user, comment)
elif action == 'unflag':
checkarg(cmdargv, 'repository name')
elif action == "unflag":
checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_unflag(pkgbase, user)
elif action == 'vote':
checkarg(cmdargv, 'repository name')
elif action == "vote":
checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_vote(pkgbase, user)
elif action == 'unvote':
checkarg(cmdargv, 'repository name')
elif action == "unvote":
checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_unvote(pkgbase, user)
elif action == 'set-comaintainers':
checkarg_atleast(cmdargv, 'repository name')
elif action == "set-comaintainers":
checkarg_atleast(cmdargv, "repository name")
pkgbase = cmdargv[1]
userlist = cmdargv[2:]
pkgbase_set_comaintainers(pkgbase, userlist, user, privileged)
elif action == 'help':
elif action == "help":
cmds = {
"adopt <name>": "Adopt a package base.",
"disown <name>": "Disown a package base.",
......@@ -575,7 +615,6 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901
"restore <name>": "Restore a deleted package base.",
"set-comaintainers <name> [...]": "Set package base co-maintainers.",
"set-keywords <name> [...]": "Change package base keywords.",
"setup-repo <name>": "Create a repository (deprecated).",
"unflag <name>": "Remove out-of-date flag from a package base.",
"unvote <name>": "Remove vote from a package base.",
"vote <name>": "Vote for a package base.",
......@@ -584,21 +623,21 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901
}
usage(cmds)
else:
msg = 'invalid command: {:s}'.format(action)
msg = "invalid command: {:s}".format(action)
raise aurweb.exceptions.InvalidArgumentsException(msg)
def main():
user = os.environ.get('AUR_USER')
privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1')
ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND')
ssh_client = os.environ.get('SSH_CLIENT')
user = os.environ.get("AUR_USER")
privileged = os.environ.get("AUR_PRIVILEGED", "0") == "1"
ssh_cmd = os.environ.get("SSH_ORIGINAL_COMMAND")
ssh_client = os.environ.get("SSH_CLIENT")
if not ssh_cmd:
die_with_help("Interactive shell is disabled.")
die_with_help(f"Welcome to AUR, {user}! Interactive shell is disabled.")
cmdargv = shlex.split(ssh_cmd)
action = cmdargv[0]
remote_addr = ssh_client.split(' ')[0] if ssh_client else None
remote_addr = ssh_client.split(" ")[0] if ssh_client else None
try:
serve(action, cmdargv, user, privileged, remote_addr)
......@@ -607,10 +646,10 @@ def main():
except aurweb.exceptions.BannedException:
die("The SSH interface is disabled for your IP address.")
except aurweb.exceptions.InvalidArgumentsException as e:
die_with_help('{:s}: {}'.format(action, e))
die_with_help("{:s}: {}".format(action, e))
except aurweb.exceptions.AurwebException as e:
die('{:s}: {}'.format(action, e))
die("{:s}: {}".format(action, e))
if __name__ == '__main__':
if __name__ == "__main__":
main()
......@@ -13,23 +13,23 @@ import srcinfo.utils
import aurweb.config
import aurweb.db
notify_cmd = aurweb.config.get('notifications', 'notify-cmd')
notify_cmd = aurweb.config.get("notifications", "notify-cmd")
repo_path = aurweb.config.get('serve', 'repo-path')
repo_regex = aurweb.config.get('serve', 'repo-regex')
repo_path = aurweb.config.get("serve", "repo-path")
repo_regex = aurweb.config.get("serve", "repo-regex")
max_blob_size = aurweb.config.getint('update', 'max-blob-size')
max_blob_size = aurweb.config.getint("update", "max-blob-size")
def size_humanize(num):
for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB']:
for unit in ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"]:
if abs(num) < 2048.0:
if isinstance(num, int):
return "{}{}".format(num, unit)
else:
return "{:.2f}{}".format(num, unit)
num /= 1024.0
return "{:.2f}{}".format(num, 'YiB')
return "{:.2f}{}".format(num, "YiB")
def extract_arch_fields(pkginfo, field):
......@@ -39,20 +39,20 @@ def extract_arch_fields(pkginfo, field):
for val in pkginfo[field]:
values.append({"value": val, "arch": None})
for arch in pkginfo['arch']:
if field + '_' + arch in pkginfo:
for val in pkginfo[field + '_' + arch]:
for arch in pkginfo["arch"]:
if field + "_" + arch in pkginfo:
for val in pkginfo[field + "_" + arch]:
values.append({"value": val, "arch": arch})
return values
def parse_dep(depstring):
dep, _, desc = depstring.partition(': ')
depname = re.sub(r'(<|=|>).*', '', dep)
depcond = dep[len(depname):]
dep, _, desc = depstring.partition(": ")
depname = re.sub(r"(<|=|>).*", "", dep)
depcond = dep[len(depname) :]
return (depname, desc, depcond)
return depname, desc, depcond
def create_pkgbase(conn, pkgbase, user):
......@@ -60,15 +60,18 @@ def create_pkgbase(conn, pkgbase, user):
userid = cur.fetchone()[0]
now = int(time.time())
cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " +
"ModifiedTS, SubmitterUID, MaintainerUID, " +
"FlaggerComment) VALUES (?, ?, ?, ?, ?, '')",
[pkgbase, now, now, userid, userid])
cur = conn.execute(
"INSERT INTO PackageBases (Name, SubmittedTS, "
+ "ModifiedTS, SubmitterUID, MaintainerUID, "
+ "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')",
[pkgbase, now, now, userid, userid],
)
pkgbase_id = cur.lastrowid
cur = conn.execute("INSERT INTO PackageNotifications " +
"(PackageBaseID, UserID) VALUES (?, ?)",
[pkgbase_id, userid])
cur = conn.execute(
"INSERT INTO PackageNotifications " + "(PackageBaseID, UserID) VALUES (?, ?)",
[pkgbase_id, userid],
)
conn.commit()
......@@ -77,9 +80,10 @@ def create_pkgbase(conn, pkgbase, user):
def save_metadata(metadata, conn, user): # noqa: C901
# Obtain package base ID and previous maintainer.
pkgbase = metadata['pkgbase']
cur = conn.execute("SELECT ID, MaintainerUID FROM PackageBases "
"WHERE Name = ?", [pkgbase])
pkgbase = metadata["pkgbase"]
cur = conn.execute(
"SELECT ID, MaintainerUID FROM PackageBases " "WHERE Name = ?", [pkgbase]
)
(pkgbase_id, maintainer_uid) = cur.fetchone()
was_orphan = not maintainer_uid
......@@ -89,119 +93,142 @@ def save_metadata(metadata, conn, user): # noqa: C901
# Update package base details and delete current packages.
now = int(time.time())
conn.execute("UPDATE PackageBases SET ModifiedTS = ?, " +
"PackagerUID = ?, OutOfDateTS = NULL WHERE ID = ?",
[now, user_id, pkgbase_id])
conn.execute("UPDATE PackageBases SET MaintainerUID = ? " +
"WHERE ID = ? AND MaintainerUID IS NULL",
[user_id, pkgbase_id])
for table in ('Sources', 'Depends', 'Relations', 'Licenses', 'Groups'):
conn.execute("DELETE FROM Package" + table + " WHERE EXISTS (" +
"SELECT * FROM Packages " +
"WHERE Packages.PackageBaseID = ? AND " +
"Package" + table + ".PackageID = Packages.ID)",
[pkgbase_id])
conn.execute(
"UPDATE PackageBases SET ModifiedTS = ?, "
+ "PackagerUID = ?, OutOfDateTS = NULL WHERE ID = ?",
[now, user_id, pkgbase_id],
)
conn.execute(
"UPDATE PackageBases SET MaintainerUID = ? "
+ "WHERE ID = ? AND MaintainerUID IS NULL",
[user_id, pkgbase_id],
)
for table in ("Sources", "Depends", "Relations", "Licenses", "Groups"):
conn.execute(
"DELETE FROM Package"
+ table
+ " WHERE EXISTS ("
+ "SELECT * FROM Packages "
+ "WHERE Packages.PackageBaseID = ? AND "
+ "Package"
+ table
+ ".PackageID = Packages.ID)",
[pkgbase_id],
)
conn.execute("DELETE FROM Packages WHERE PackageBaseID = ?", [pkgbase_id])
for pkgname in srcinfo.utils.get_package_names(metadata):
pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata)
if 'epoch' in pkginfo and int(pkginfo['epoch']) > 0:
ver = '{:d}:{:s}-{:s}'.format(int(pkginfo['epoch']),
pkginfo['pkgver'],
pkginfo['pkgrel'])
if "epoch" in pkginfo and int(pkginfo["epoch"]) > 0:
ver = "{:d}:{:s}-{:s}".format(
int(pkginfo["epoch"]), pkginfo["pkgver"], pkginfo["pkgrel"]
)
else:
ver = '{:s}-{:s}'.format(pkginfo['pkgver'], pkginfo['pkgrel'])
ver = "{:s}-{:s}".format(pkginfo["pkgver"], pkginfo["pkgrel"])
for field in ('pkgdesc', 'url'):
for field in ("pkgdesc", "url"):
if field not in pkginfo:
pkginfo[field] = None
# Create a new package.
cur = conn.execute("INSERT INTO Packages (PackageBaseID, Name, " +
"Version, Description, URL) " +
"VALUES (?, ?, ?, ?, ?)",
[pkgbase_id, pkginfo['pkgname'], ver,
pkginfo['pkgdesc'], pkginfo['url']])
cur = conn.execute(
"INSERT INTO Packages (PackageBaseID, Name, "
+ "Version, Description, URL) "
+ "VALUES (?, ?, ?, ?, ?)",
[pkgbase_id, pkginfo["pkgname"], ver, pkginfo["pkgdesc"], pkginfo["url"]],
)
conn.commit()
pkgid = cur.lastrowid
# Add package sources.
for source_info in extract_arch_fields(pkginfo, 'source'):
conn.execute("INSERT INTO PackageSources (PackageID, Source, " +
"SourceArch) VALUES (?, ?, ?)",
[pkgid, source_info['value'], source_info['arch']])
for source_info in extract_arch_fields(pkginfo, "source"):
conn.execute(
"INSERT INTO PackageSources (PackageID, Source, "
+ "SourceArch) VALUES (?, ?, ?)",
[pkgid, source_info["value"], source_info["arch"]],
)
# Add package dependencies.
for deptype in ('depends', 'makedepends',
'checkdepends', 'optdepends'):
cur = conn.execute("SELECT ID FROM DependencyTypes WHERE Name = ?",
[deptype])
for deptype in ("depends", "makedepends", "checkdepends", "optdepends"):
cur = conn.execute(
"SELECT ID FROM DependencyTypes WHERE Name = ?", [deptype]
)
deptypeid = cur.fetchone()[0]
for dep_info in extract_arch_fields(pkginfo, deptype):
depname, depdesc, depcond = parse_dep(dep_info['value'])
deparch = dep_info['arch']
conn.execute("INSERT INTO PackageDepends (PackageID, " +
"DepTypeID, DepName, DepDesc, DepCondition, " +
"DepArch) VALUES (?, ?, ?, ?, ?, ?)",
[pkgid, deptypeid, depname, depdesc, depcond,
deparch])
depname, depdesc, depcond = parse_dep(dep_info["value"])
deparch = dep_info["arch"]
conn.execute(
"INSERT INTO PackageDepends (PackageID, "
+ "DepTypeID, DepName, DepDesc, DepCondition, "
+ "DepArch) VALUES (?, ?, ?, ?, ?, ?)",
[pkgid, deptypeid, depname, depdesc, depcond, deparch],
)
# Add package relations (conflicts, provides, replaces).
for reltype in ('conflicts', 'provides', 'replaces'):
cur = conn.execute("SELECT ID FROM RelationTypes WHERE Name = ?",
[reltype])
for reltype in ("conflicts", "provides", "replaces"):
cur = conn.execute("SELECT ID FROM RelationTypes WHERE Name = ?", [reltype])
reltypeid = cur.fetchone()[0]
for rel_info in extract_arch_fields(pkginfo, reltype):
relname, _, relcond = parse_dep(rel_info['value'])
relarch = rel_info['arch']
conn.execute("INSERT INTO PackageRelations (PackageID, " +
"RelTypeID, RelName, RelCondition, RelArch) " +
"VALUES (?, ?, ?, ?, ?)",
[pkgid, reltypeid, relname, relcond, relarch])
relname, _, relcond = parse_dep(rel_info["value"])
relarch = rel_info["arch"]
conn.execute(
"INSERT INTO PackageRelations (PackageID, "
+ "RelTypeID, RelName, RelCondition, RelArch) "
+ "VALUES (?, ?, ?, ?, ?)",
[pkgid, reltypeid, relname, relcond, relarch],
)
# Add package licenses.
if 'license' in pkginfo:
for license in pkginfo['license']:
cur = conn.execute("SELECT ID FROM Licenses WHERE Name = ?",
[license])
if "license" in pkginfo:
for license in pkginfo["license"]:
cur = conn.execute("SELECT ID FROM Licenses WHERE Name = ?", [license])
row = cur.fetchone()
if row:
licenseid = row[0]
else:
cur = conn.execute("INSERT INTO Licenses (Name) " +
"VALUES (?)", [license])
cur = conn.execute(
"INSERT INTO Licenses (Name) " + "VALUES (?)", [license]
)
conn.commit()
licenseid = cur.lastrowid
conn.execute("INSERT INTO PackageLicenses (PackageID, " +
"LicenseID) VALUES (?, ?)",
[pkgid, licenseid])
conn.execute(
"INSERT INTO PackageLicenses (PackageID, "
+ "LicenseID) VALUES (?, ?)",
[pkgid, licenseid],
)
# Add package groups.
if 'groups' in pkginfo:
for group in pkginfo['groups']:
cur = conn.execute("SELECT ID FROM `Groups` WHERE Name = ?",
[group])
if "groups" in pkginfo:
for group in pkginfo["groups"]:
cur = conn.execute("SELECT ID FROM `Groups` WHERE Name = ?", [group])
row = cur.fetchone()
if row:
groupid = row[0]
else:
cur = conn.execute("INSERT INTO `Groups` (Name) VALUES (?)",
[group])
cur = conn.execute(
"INSERT INTO `Groups` (Name) VALUES (?)", [group]
)
conn.commit()
groupid = cur.lastrowid
conn.execute("INSERT INTO PackageGroups (PackageID, "
"GroupID) VALUES (?, ?)", [pkgid, groupid])
conn.execute(
"INSERT INTO PackageGroups (PackageID, " "GroupID) VALUES (?, ?)",
[pkgid, groupid],
)
# Add user to notification list on adoption.
if was_orphan:
cur = conn.execute("SELECT COUNT(*) FROM PackageNotifications WHERE " +
"PackageBaseID = ? AND UserID = ?",
[pkgbase_id, user_id])
cur = conn.execute(
"SELECT COUNT(*) FROM PackageNotifications WHERE "
+ "PackageBaseID = ? AND UserID = ?",
[pkgbase_id, user_id],
)
if cur.fetchone()[0] == 0:
conn.execute("INSERT INTO PackageNotifications " +
"(PackageBaseID, UserID) VALUES (?, ?)",
[pkgbase_id, user_id])
conn.execute(
"INSERT INTO PackageNotifications "
+ "(PackageBaseID, UserID) VALUES (?, ?)",
[pkgbase_id, user_id],
)
conn.commit()
......@@ -212,7 +239,7 @@ def update_notify(conn, user, pkgbase_id):
user_id = int(cur.fetchone()[0])
# Execute the notification script.
subprocess.Popen((notify_cmd, 'update', str(user_id), str(pkgbase_id)))
subprocess.Popen((notify_cmd, "update", str(user_id), str(pkgbase_id)))
def die(msg):
......@@ -225,28 +252,91 @@ def warn(msg):
def die_commit(msg, commit):
sys.stderr.write("error: The following error " +
"occurred when parsing commit\n")
sys.stderr.write("error: The following error " + "occurred when parsing commit\n")
sys.stderr.write("error: {:s}:\n".format(commit))
sys.stderr.write("error: {:s}\n".format(msg))
exit(1)
def validate_metadata(metadata, commit): # noqa: C901
try:
metadata_pkgbase = metadata["pkgbase"]
except KeyError:
die_commit(
"invalid .SRCINFO, does not contain a pkgbase (is the file empty?)",
str(commit.id),
)
if not re.match(repo_regex, metadata_pkgbase):
die_commit("invalid pkgbase: {:s}".format(metadata_pkgbase), str(commit.id))
if not metadata["packages"]:
die_commit("missing pkgname entry", str(commit.id))
for pkgname in set(metadata["packages"].keys()):
pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata)
for field in ("pkgver", "pkgrel", "pkgname"):
if field not in pkginfo:
die_commit(
"missing mandatory field: {:s}".format(field), str(commit.id)
)
if "epoch" in pkginfo and not pkginfo["epoch"].isdigit():
die_commit("invalid epoch: {:s}".format(pkginfo["epoch"]), str(commit.id))
if not re.match(r"[a-z0-9][a-z0-9\.+_-]*$", pkginfo["pkgname"]):
die_commit(
"invalid package name: {:s}".format(pkginfo["pkgname"]),
str(commit.id),
)
max_len = {"pkgname": 255, "pkgdesc": 255, "url": 8000}
for field in max_len.keys():
if field in pkginfo and len(pkginfo[field]) > max_len[field]:
die_commit(
"{:s} field too long: {:s}".format(field, pkginfo[field]),
str(commit.id),
)
for field in ("install", "changelog"):
if field in pkginfo and not pkginfo[field] in commit.tree:
die_commit(
"missing {:s} file: {:s}".format(field, pkginfo[field]),
str(commit.id),
)
for field in extract_arch_fields(pkginfo, "source"):
fname = field["value"]
if len(fname) > 8000:
die_commit("source entry too long: {:s}".format(fname), str(commit.id))
if "://" in fname or "lp:" in fname:
continue
if fname not in commit.tree:
die_commit("missing source file: {:s}".format(fname), str(commit.id))
def validate_blob_size(blob: pygit2.Object, commit: pygit2.Commit):
if isinstance(blob, pygit2.Blob) and blob.size > max_blob_size:
die_commit(
"maximum blob size ({:s}) exceeded".format(size_humanize(max_blob_size)),
str(commit.id),
)
def main(): # noqa: C901
repo = pygit2.Repository(repo_path)
user = os.environ.get("AUR_USER")
pkgbase = os.environ.get("AUR_PKGBASE")
privileged = (os.environ.get("AUR_PRIVILEGED", '0') == '1')
allow_overwrite = (os.environ.get("AUR_OVERWRITE", '0') == '1') and privileged
privileged = os.environ.get("AUR_PRIVILEGED", "0") == "1"
allow_overwrite = (os.environ.get("AUR_OVERWRITE", "0") == "1") and privileged
warn_or_die = warn if privileged else die
if len(sys.argv) == 2 and sys.argv[1] == "restore":
if 'refs/heads/' + pkgbase not in repo.listall_references():
die('{:s}: repository not found: {:s}'.format(sys.argv[1],
pkgbase))
if "refs/heads/" + pkgbase not in repo.listall_references():
die("{:s}: repository not found: {:s}".format(sys.argv[1], pkgbase))
refname = "refs/heads/master"
branchref = 'refs/heads/' + pkgbase
branchref = "refs/heads/" + pkgbase
sha1_old = sha1_new = repo.lookup_reference(branchref).target
elif len(sys.argv) == 4:
refname, sha1_old, sha1_new = sys.argv[1:4]
......@@ -266,137 +356,115 @@ def main(): # noqa: C901
die("denying non-fast-forward (you should pull first)")
# Prepare the walker that validates new commits.
walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL)
walker = repo.walk(sha1_new, pygit2.GIT_SORT_REVERSE)
if sha1_old != "0" * 40:
walker.hide(sha1_old)
head_commit = repo[sha1_new]
if ".SRCINFO" not in head_commit.tree:
die_commit("missing .SRCINFO", str(head_commit.id))
# Read .SRCINFO from the HEAD commit.
metadata_raw = repo[head_commit.tree[".SRCINFO"].id].data.decode()
(metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw)
if errors:
sys.stderr.write(
"error: The following errors occurred " "when parsing .SRCINFO in commit\n"
)
sys.stderr.write("error: {:s}:\n".format(str(head_commit.id)))
for error in errors:
for err in error["error"]:
sys.stderr.write("error: line {:d}: {:s}\n".format(error["line"], err))
exit(1)
# check if there is a correct .SRCINFO file in the latest revision
validate_metadata(metadata, head_commit)
# Validate all new commits.
for commit in walker:
for fname in ('.SRCINFO', 'PKGBUILD'):
if fname not in commit.tree:
die_commit("missing {:s}".format(fname), str(commit.id))
if "PKGBUILD" not in commit.tree:
die_commit("missing PKGBUILD", str(commit.id))
# Iterate over files in root dir
for treeobj in commit.tree:
blob = repo[treeobj.id]
if isinstance(blob, pygit2.Tree):
die_commit("the repository must not contain subdirectories",
str(commit.id))
if not isinstance(blob, pygit2.Blob):
die_commit("not a blob object: {:s}".format(treeobj),
str(commit.id))
if blob.size > max_blob_size:
die_commit("maximum blob size ({:s}) exceeded".format(
size_humanize(max_blob_size)), str(commit.id))
metadata_raw = repo[commit.tree['.SRCINFO'].id].data.decode()
(metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw)
if errors:
sys.stderr.write("error: The following errors occurred "
"when parsing .SRCINFO in commit\n")
sys.stderr.write("error: {:s}:\n".format(str(commit.id)))
for error in errors:
for err in error['error']:
sys.stderr.write("error: line {:d}: {:s}\n".format(
error['line'], err))
exit(1)
try:
metadata_pkgbase = metadata['pkgbase']
except KeyError as e:
die_commit('invalid .SRCINFO, does not contain a pkgbase (is the file empty?)',
str(commit.id))
if not re.match(repo_regex, metadata_pkgbase):
die_commit('invalid pkgbase: {:s}'.format(metadata_pkgbase),
str(commit.id))
if not metadata['packages']:
die_commit('missing pkgname entry', str(commit.id))
for pkgname in set(metadata['packages'].keys()):
pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata)
for field in ('pkgver', 'pkgrel', 'pkgname'):
if field not in pkginfo:
die_commit('missing mandatory field: {:s}'.format(field),
str(commit.id))
if 'epoch' in pkginfo and not pkginfo['epoch'].isdigit():
die_commit('invalid epoch: {:s}'.format(pkginfo['epoch']),
str(commit.id))
if not re.match(r'[a-z0-9][a-z0-9\.+_-]*$', pkginfo['pkgname']):
die_commit('invalid package name: {:s}'.format(
pkginfo['pkgname']), str(commit.id))
max_len = {'pkgname': 255, 'pkgdesc': 255, 'url': 8000}
for field in max_len.keys():
if field in pkginfo and len(pkginfo[field]) > max_len[field]:
die_commit('{:s} field too long: {:s}'.format(field,
pkginfo[field]), str(commit.id))
for field in ('install', 'changelog'):
if field in pkginfo and not pkginfo[field] in commit.tree:
die_commit('missing {:s} file: {:s}'.format(field,
pkginfo[field]), str(commit.id))
for field in extract_arch_fields(pkginfo, 'source'):
fname = field['value']
if len(fname) > 8000:
die_commit('source entry too long: {:s}'.format(fname),
str(commit.id))
if "://" in fname or "lp:" in fname:
continue
if fname not in commit.tree:
die_commit('missing source file: {:s}'.format(fname),
str(commit.id))
# Don't allow any subdirs besides "keys/"
if isinstance(treeobj, pygit2.Tree) and treeobj.name != "keys":
die_commit(
"the repository must not contain subdirectories",
str(commit.id),
)
# Check size of files in root dir
validate_blob_size(treeobj, commit)
# If we got a subdir keys/,
# make sure it only contains a pgp/ subdir with key files
if "keys" in commit.tree:
# Check for forbidden files/dirs in keys/
for keyobj in commit.tree["keys"]:
if not isinstance(keyobj, pygit2.Tree) or keyobj.name != "pgp":
die_commit(
"the keys/ subdir may only contain a pgp/ directory",
str(commit.id),
)
# Check for forbidden files in keys/pgp/
if "keys/pgp" in commit.tree:
for pgpobj in commit.tree["keys/pgp"]:
if not isinstance(pgpobj, pygit2.Blob) or not pgpobj.name.endswith(
".asc"
):
die_commit(
"the subdir may only contain .asc (PGP pub key) files",
str(commit.id),
)
# Check file size for pgp key files
validate_blob_size(pgpobj, commit)
# Display a warning if .SRCINFO is unchanged.
if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new):
srcinfo_id_old = repo[sha1_old].tree['.SRCINFO'].id
srcinfo_id_new = repo[sha1_new].tree['.SRCINFO'].id
srcinfo_id_old = repo[sha1_old].tree[".SRCINFO"].id
srcinfo_id_new = repo[sha1_new].tree[".SRCINFO"].id
if srcinfo_id_old == srcinfo_id_new:
warn(".SRCINFO unchanged. "
"The package database will not be updated!")
# Read .SRCINFO from the HEAD commit.
metadata_raw = repo[repo[sha1_new].tree['.SRCINFO'].id].data.decode()
(metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw)
warn(".SRCINFO unchanged. " "The package database will not be updated!")
# Ensure that the package base name matches the repository name.
metadata_pkgbase = metadata['pkgbase']
metadata_pkgbase = metadata["pkgbase"]
if metadata_pkgbase != pkgbase:
die('invalid pkgbase: {:s}, expected {:s}'.format(metadata_pkgbase,
pkgbase))
die("invalid pkgbase: {:s}, expected {:s}".format(metadata_pkgbase, pkgbase))
# Ensure that packages are neither blacklisted nor overwritten.
pkgbase = metadata['pkgbase']
pkgbase = metadata["pkgbase"]
cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase])
row = cur.fetchone()
pkgbase_id = row[0] if row else 0
cur = conn.execute("SELECT Name FROM PackageBlacklist")
blacklist = [row[0] for row in cur.fetchall()]
if pkgbase in blacklist:
warn_or_die("pkgbase is blacklisted: {:s}".format(pkgbase))
cur = conn.execute("SELECT Name, Repo FROM OfficialProviders")
providers = dict(cur.fetchall())
for pkgname in srcinfo.utils.get_package_names(metadata):
pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata)
pkgname = pkginfo['pkgname']
pkgname = pkginfo["pkgname"]
if pkgname in blacklist:
warn_or_die('package is blacklisted: {:s}'.format(pkgname))
warn_or_die("package is blacklisted: {:s}".format(pkgname))
if pkgname in providers:
warn_or_die('package already provided by [{:s}]: {:s}'.format(
providers[pkgname], pkgname))
cur = conn.execute("SELECT COUNT(*) FROM Packages WHERE Name = ? " +
"AND PackageBaseID <> ?", [pkgname, pkgbase_id])
warn_or_die(
"package already provided by [{:s}]: {:s}".format(
providers[pkgname], pkgname
)
)
cur = conn.execute(
"SELECT COUNT(*) FROM Packages WHERE Name = ? " + "AND PackageBaseID <> ?",
[pkgname, pkgbase_id],
)
if cur.fetchone()[0] > 0:
die('cannot overwrite package: {:s}'.format(pkgname))
die("cannot overwrite package: {:s}".format(pkgname))
# Create a new package base if it does not exist yet.
if pkgbase_id == 0:
......@@ -407,7 +475,7 @@ def main(): # noqa: C901
# Create (or update) a branch with the name of the package base for better
# accessibility.
branchref = 'refs/heads/' + pkgbase
branchref = "refs/heads/" + pkgbase
repo.create_reference(branchref, sha1_new, True)
# Work around a Git bug: The HEAD ref is not updated when using
......@@ -415,7 +483,7 @@ def main(): # noqa: C901
# mainline. See
# http://git.661346.n2.nabble.com/PATCH-receive-pack-Create-a-HEAD-ref-for-ref-namespace-td7632149.html
# for details.
headref = 'refs/namespaces/' + pkgbase + '/HEAD'
headref = "refs/namespaces/" + pkgbase + "/HEAD"
repo.create_reference(headref, sha1_new, True)
# Send package update notifications.
......@@ -426,5 +494,5 @@ def main(): # noqa: C901
conn.close()
if __name__ == '__main__':
if __name__ == "__main__":
main()
......@@ -2,62 +2,82 @@ import argparse
import alembic.command
import alembic.config
import sqlalchemy
import aurweb.aur_logging
import aurweb.db
import aurweb.schema
def feed_initial_data(conn):
conn.execute(aurweb.schema.AccountTypes.insert(), [
{'ID': 1, 'AccountType': 'User'},
{'ID': 2, 'AccountType': 'Trusted User'},
{'ID': 3, 'AccountType': 'Developer'},
{'ID': 4, 'AccountType': 'Trusted User & Developer'},
])
conn.execute(aurweb.schema.DependencyTypes.insert(), [
{'ID': 1, 'Name': 'depends'},
{'ID': 2, 'Name': 'makedepends'},
{'ID': 3, 'Name': 'checkdepends'},
{'ID': 4, 'Name': 'optdepends'},
])
conn.execute(aurweb.schema.RelationTypes.insert(), [
{'ID': 1, 'Name': 'conflicts'},
{'ID': 2, 'Name': 'provides'},
{'ID': 3, 'Name': 'replaces'},
])
conn.execute(aurweb.schema.RequestTypes.insert(), [
{'ID': 1, 'Name': 'deletion'},
{'ID': 2, 'Name': 'orphan'},
{'ID': 3, 'Name': 'merge'},
])
conn.execute(
aurweb.schema.AccountTypes.insert(),
[
{"ID": 1, "AccountType": "User"},
{"ID": 2, "AccountType": "Package Maintainer"},
{"ID": 3, "AccountType": "Developer"},
{"ID": 4, "AccountType": "Package Maintainer & Developer"},
],
)
conn.execute(
aurweb.schema.DependencyTypes.insert(),
[
{"ID": 1, "Name": "depends"},
{"ID": 2, "Name": "makedepends"},
{"ID": 3, "Name": "checkdepends"},
{"ID": 4, "Name": "optdepends"},
],
)
conn.execute(
aurweb.schema.RelationTypes.insert(),
[
{"ID": 1, "Name": "conflicts"},
{"ID": 2, "Name": "provides"},
{"ID": 3, "Name": "replaces"},
],
)
conn.execute(
aurweb.schema.RequestTypes.insert(),
[
{"ID": 1, "Name": "deletion"},
{"ID": 2, "Name": "orphan"},
{"ID": 3, "Name": "merge"},
],
)
def run(args):
aurweb.config.rehash()
# Ensure Alembic is fine before we do the real work, in order not to fail at
# the last step and leave the database in an inconsistent state. The
# configuration is loaded lazily, so we query it to force its loading.
if args.use_alembic:
alembic_config = alembic.config.Config('alembic.ini')
alembic_config.get_main_option('script_location')
alembic_config = alembic.config.Config("alembic.ini")
alembic_config.get_main_option("script_location")
alembic_config.attributes["configure_logger"] = False
engine = sqlalchemy.create_engine(aurweb.db.get_sqlalchemy_url(),
echo=(args.verbose >= 1))
engine = aurweb.db.get_engine(echo=(args.verbose >= 1))
aurweb.schema.metadata.create_all(engine)
feed_initial_data(engine.connect())
conn = engine.connect()
feed_initial_data(conn)
conn.close()
if args.use_alembic:
alembic.command.stamp(alembic_config, 'head')
alembic.command.stamp(alembic_config, "head")
if __name__ == '__main__':
if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog='python -m aurweb.initdb',
description='Initialize the aurweb database.')
parser.add_argument('-v', '--verbose', action='count', default=0,
help='increase verbosity')
parser.add_argument('--no-alembic',
help='disable Alembic migrations support',
dest='use_alembic', action='store_false')
prog="python -m aurweb.initdb", description="Initialize the aurweb database."
)
parser.add_argument(
"-v", "--verbose", action="count", default=0, help="increase verbosity"
)
parser.add_argument(
"--no-alembic",
help="disable Alembic migrations support",
dest="use_alembic",
action="store_false",
)
args = parser.parse_args()
run(args)
import gettext
from collections import OrderedDict
from fastapi import Request
import aurweb.config
SUPPORTED_LANGUAGES = OrderedDict(
{
"ar": "العربية",
"ast": "Asturianu",
"ca": "Català",
"cs": "Český",
"da": "Dansk",
"de": "Deutsch",
"el": "Ελληνικά",
"en": "English",
"es": "Español",
"es_419": "Español (Latinoamérica)",
"fi": "Suomi",
"fr": "Français",
"he": "עברית",
"hr": "Hrvatski",
"hu": "Magyar",
"it": "Italiano",
"ja": "日本語",
"nb": "Norsk",
"nl": "Nederlands",
"pl": "Polski",
"pt_BR": "Português (Brasil)",
"pt_PT": "Português (Portugal)",
"ro": "Română",
"ru": "Русский",
"sk": "Slovenčina",
"sr": "Srpski",
"tr": "Türkçe",
"uk": "Українська",
"zh_CN": "简体中文",
"zh_TW": "正體中文",
}
)
RIGHT_TO_LEFT_LANGUAGES = ("he", "ar")
class Translator:
def __init__(self):
self._localedir = aurweb.config.get('options', 'localedir')
self._localedir = aurweb.config.get("options", "localedir")
self._translator = {}
def translate(self, s, lang):
if lang == 'en':
return s
def get_translator(self, lang: str):
if lang not in self._translator:
self._translator[lang] = gettext.translation("aurweb",
self._localedir,
languages=[lang])
return self._translator[lang].gettext(s)
self._translator[lang] = gettext.translation(
"aurweb", self._localedir, languages=[lang], fallback=True
)
return self._translator.get(lang)
def translate(self, s: str, lang: str):
return self.get_translator(lang).gettext(s)
# Global translator object.
translator = Translator()
def get_translator_for_request(request):
def get_request_language(request: Request) -> str:
"""Get a request's language from either query param, user setting or
cookie. We use the configuration's [options] default_lang otherwise.
@param request FastAPI request
"""
request_lang = request.query_params.get("language")
cookie_lang = request.cookies.get("AURLANG")
if request_lang and request_lang in SUPPORTED_LANGUAGES:
return request_lang
elif (
request.user.is_authenticated()
and request.user.LangPreference in SUPPORTED_LANGUAGES
):
return request.user.LangPreference
elif cookie_lang and cookie_lang in SUPPORTED_LANGUAGES:
return cookie_lang
return aurweb.config.get_with_fallback("options", "default_lang", "en")
def get_raw_translator_for_request(request: Request):
lang = get_request_language(request)
return translator.get_translator(lang)
def get_translator_for_request(request: Request):
"""
Determine the preferred language from a FastAPI request object and build a
translator function for it.
Example:
```python
_ = get_translator_for_request(request)
print(_("Hello"))
```
"""
lang = request.cookies.get("AURLANG")
if lang is None:
lang = aurweb.config.get("options", "default_lang")
translator = Translator()
lang = get_request_language(request)
def translate(message):
return translator.translate(message, lang)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.