serve.py 20.9 KB
Newer Older
1
2
3
4
5
#!/usr/bin/python3

import os
import re
import shlex
6
import subprocess
7
import sys
8
import time
9

10
11
import aurweb.config
import aurweb.db
12
import aurweb.exceptions
13

14
notify_cmd = aurweb.config.get('notifications', 'notify-cmd')
15

16
17
18
19
20
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')
21

22
23
enable_maintenance = aurweb.config.getboolean('options', 'enable-maintenance')
maintenance_exc = aurweb.config.get('options', 'maintenance-exceptions').split()
Lukas Fleischer's avatar
Lukas Fleischer committed
24

25

26
def pkgbase_from_name(pkgbase):
27
    conn = aurweb.db.Connection()
28
    cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase])
29

30
31
    row = cur.fetchone()
    return row[0] if row else None
32

33

34
def pkgbase_exists(pkgbase):
Mark Weiman's avatar
Mark Weiman committed
35
    return pkgbase_from_name(pkgbase) is not None
36

37

38
def list_repos(user):
39
    conn = aurweb.db.Connection()
40

41
    cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
42
43
    userid = cur.fetchone()[0]
    if userid == 0:
44
        raise aurweb.exceptions.InvalidUserException(user)
45

46
47
    cur = conn.execute("SELECT Name, PackagerUID FROM PackageBases " +
                       "WHERE MaintainerUID = ?", [userid])
48
49
    for row in cur:
        print((' ' if row[1] else '*') + row[0])
50
    conn.close()
51

52

53
def create_pkgbase(pkgbase, user):
54
    if not re.match(repo_regex, pkgbase):
55
        raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase)
56
    if pkgbase_exists(pkgbase):
57
        raise aurweb.exceptions.PackageBaseExistsException(pkgbase)
58

59
    conn = aurweb.db.Connection()
60

61
    cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
62
63
    userid = cur.fetchone()[0]
    if userid == 0:
64
        raise aurweb.exceptions.InvalidUserException(user)
65

66
    now = int(time.time())
67
    cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " +
68
69
70
                       "ModifiedTS, SubmitterUID, MaintainerUID, " +
                       "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')",
                       [pkgbase, now, now, userid, userid])
71
72
    pkgbase_id = cur.lastrowid

73
74
75
    cur = conn.execute("INSERT INTO PackageNotifications " +
                       "(PackageBaseID, UserID) VALUES (?, ?)",
                       [pkgbase_id, userid])
76

77
78
    conn.commit()
    conn.close()
79

80

81
def pkgbase_adopt(pkgbase, user, privileged):
82
83
    pkgbase_id = pkgbase_from_name(pkgbase)
    if not pkgbase_id:
84
        raise aurweb.exceptions.InvalidPackageBaseException(pkgbase)
85

86
    conn = aurweb.db.Connection()
87
88
89
90

    cur = conn.execute("SELECT ID FROM PackageBases WHERE ID = ? AND " +
                       "MaintainerUID IS NULL", [pkgbase_id])
    if not privileged and not cur.fetchone():
91
        raise aurweb.exceptions.PermissionDeniedException(user)
92
93
94
95

    cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
    userid = cur.fetchone()[0]
    if userid == 0:
96
        raise aurweb.exceptions.InvalidUserException(user)
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

    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])
    if cur.fetchone()[0] == 0:
        cur = conn.execute("INSERT INTO PackageNotifications " +
                           "(PackageBaseID, UserID) VALUES (?, ?)",
                           [pkgbase_id, userid])
    conn.commit()

    subprocess.Popen((notify_cmd, 'adopt', str(pkgbase_id), str(userid)))

    conn.close()


115
def pkgbase_get_comaintainers(pkgbase):
116
    conn = aurweb.db.Connection()
117
118
119
120
121
122
123
124
125
126
127
128

    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()]


129
def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
130
131
    pkgbase_id = pkgbase_from_name(pkgbase)
    if not pkgbase_id:
132
        raise aurweb.exceptions.InvalidPackageBaseException(pkgbase)
133
134

    if not privileged and not pkgbase_has_full_access(pkgbase, user):
135
        raise aurweb.exceptions.PermissionDeniedException(user)
136

137
    conn = aurweb.db.Connection()
138
139
140
141
142
143
144
145
146

    userlist_old = set(pkgbase_get_comaintainers(pkgbase))

    uids_old = set()
    for olduser in userlist_old:
        cur = conn.execute("SELECT ID FROM Users WHERE Username = ?",
                           [olduser])
        userid = cur.fetchone()[0]
        if userid == 0:
147
            raise aurweb.exceptions.InvalidUserException(user)
148
149
150
151
152
153
154
155
        uids_old.add(userid)

    uids_new = set()
    for newuser in userlist:
        cur = conn.execute("SELECT ID FROM Users WHERE Username = ?",
                           [newuser])
        userid = cur.fetchone()[0]
        if userid == 0:
156
            raise aurweb.exceptions.InvalidUserException(user)
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
        uids_new.add(userid)

    uids_add = uids_new - uids_old
    uids_rem = uids_old - uids_new

    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(pkgbase_id),
                              str(userid)))
        else:
            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(pkgbase_id), str(userid)))

    conn.commit()
    conn.close()


188
189
190
191
192
193
194
195
196
197
198
199
200
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])

    return [row[0] for row in cur.fetchall()]


201
def pkgreq_close(reqid, user, reason, comments, autoclose=False):
202
203
    statusmap = {'accepted': 2, 'rejected': 3}
    if reason not in statusmap:
204
        raise aurweb.exceptions.InvalidReasonException(reason)
205
206
207
208
209
210
211
212
213
214
    status = statusmap[reason]

    conn = aurweb.db.Connection()

    if autoclose:
        userid = 0
    else:
        cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
        userid = cur.fetchone()[0]
        if userid == 0:
215
            raise aurweb.exceptions.InvalidUserException(user)
216
217
218
219
220
221
222
223
224
225

    conn.execute("UPDATE PackageRequests SET Status = ?, ClosureComment = ? " +
                 "WHERE ID = ?", [status, comments, reqid])
    conn.commit()
    conn.close()

    subprocess.Popen((notify_cmd, 'request-close', str(userid), str(reqid),
                      reason)).wait()


226
def pkgbase_disown(pkgbase, user, privileged):
227
228
    pkgbase_id = pkgbase_from_name(pkgbase)
    if not pkgbase_id:
229
        raise aurweb.exceptions.InvalidPackageBaseException(pkgbase)
230
231
232

    initialized_by_owner = pkgbase_has_full_access(pkgbase, user)
    if not privileged and not initialized_by_owner:
233
        raise aurweb.exceptions.PermissionDeniedException(user)
234
235

    # TODO: Support disowning package bases via package request.
236
237
238
239

    # 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'):
240
        pkgreq_close(reqid, user, 'accepted', comment, True)
241
242
243
244

    comaintainers = []
    new_maintainer_userid = None

245
    conn = aurweb.db.Connection()
246
247
248
249
250
251
252
253
254
255
256
257

    # Make the first co-maintainer the new maintainer, unless the action was
    # enforced by a Trusted User.
    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])
            new_maintainer_userid = cur.fetchone()[0]
            comaintainers.remove(new_maintainer)

258
    pkgbase_set_comaintainers(pkgbase, comaintainers, user, privileged)
259
260
261
262
263
264
265
266
    cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " +
                       "WHERE ID = ?", [new_maintainer_userid, pkgbase_id])

    conn.commit()

    cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
    userid = cur.fetchone()[0]
    if userid == 0:
267
            raise aurweb.exceptions.InvalidUserException(user)
268
269
270
271
272
273

    subprocess.Popen((notify_cmd, 'disown', str(pkgbase_id), str(userid)))

    conn.close()


274
275
276
def pkgbase_flag(pkgbase, user, comment):
    pkgbase_id = pkgbase_from_name(pkgbase)
    if not pkgbase_id:
277
278
279
        raise aurweb.exceptions.InvalidPackageBaseException(pkgbase)
    if len(comment) < 3:
        raise aurweb.exceptions.InvalidCommentException(comment)
280
281
282
283
284
285

    conn = aurweb.db.Connection()

    cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
    userid = cur.fetchone()[0]
    if userid == 0:
286
        raise aurweb.exceptions.InvalidUserException(user)
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301

    now = int(time.time())
    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)))


def pkgbase_unflag(pkgbase, user):
    pkgbase_id = pkgbase_from_name(pkgbase)
    if not pkgbase_id:
302
        raise aurweb.exceptions.InvalidPackageBaseException(pkgbase)
303
304
305
306
307
308

    conn = aurweb.db.Connection()

    cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
    userid = cur.fetchone()[0]
    if userid == 0:
309
        raise aurweb.exceptions.InvalidUserException(user)
310
311
312
313
314
315
316
317
318
319
320
321

    if user in pkgbase_get_comaintainers(pkgbase):
        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.commit()


322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
def pkgbase_vote(pkgbase, user):
    pkgbase_id = pkgbase_from_name(pkgbase)
    if not pkgbase_id:
        raise aurweb.exceptions.InvalidPackageBaseException(pkgbase)

    conn = aurweb.db.Connection()

    cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
    userid = cur.fetchone()[0]
    if userid == 0:
        raise aurweb.exceptions.InvalidUserException(user)

    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.commit()


def pkgbase_unvote(pkgbase, user):
    pkgbase_id = pkgbase_from_name(pkgbase)
    if not pkgbase_id:
        raise aurweb.exceptions.InvalidPackageBaseException(pkgbase)

    conn = aurweb.db.Connection()

    cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user])
    userid = cur.fetchone()[0]
    if userid == 0:
        raise aurweb.exceptions.InvalidUserException(user)

    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.commit()


373
def pkgbase_set_keywords(pkgbase, keywords):
374
375
    pkgbase_id = pkgbase_from_name(pkgbase)
    if not pkgbase_id:
376
        raise aurweb.exceptions.InvalidPackageBaseException(pkgbase)
377

378
    conn = aurweb.db.Connection()
379

380
381
    conn.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = ?",
                 [pkgbase_id])
382
    for keyword in keywords:
383
384
        conn.execute("INSERT INTO PackageKeywords (PackageBaseID, Keyword) " +
                     "VALUES (?, ?)", [pkgbase_id, keyword])
385

386
387
    conn.commit()
    conn.close()
388

389

390
def pkgbase_has_write_access(pkgbase, user):
391
    conn = aurweb.db.Connection()
392
393
394
395
396
397
398
399
400

    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])
401
402
    return cur.fetchone()[0] > 0

403

404
def pkgbase_has_full_access(pkgbase, user):
405
    conn = aurweb.db.Connection()
406
407
408
409
410
411
412
413

    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


414
415
416
417
418
419
420
421
422
423
424
425
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.commit()
    conn.close()


426
427
428
429
430
431
432
433
def bans_match(remote_addr):
    conn = aurweb.db.Connection()

    cur = conn.execute("SELECT COUNT(*) FROM Bans WHERE IPAddress = ?",
                       [remote_addr])
    return cur.fetchone()[0] > 0


434
def die(msg):
435
    sys.stderr.write("{:s}\n".format(msg))
436
437
    exit(1)

438

439
def die_with_help(msg):
440
    die(msg + "\nTry `{:s} help` for a list of commands.".format(ssh_cmdline))
441

442

443
444
445
446
def warn(msg):
    sys.stderr.write("warning: {:s}\n".format(msg))


447
448
449
450
451
452
453
454
def usage(cmds):
    sys.stderr.write("Commands:\n")
    colwidth = max([len(cmd) for cmd in cmds.keys()]) + 4
    for key in sorted(cmds):
        sys.stderr.write("  " + key.ljust(colwidth) + cmds[key] + "\n")
    exit(0)


455
456
457
458
459
460
461
462
463
def checkarg_atleast(cmdargv, *argdesc):
    if len(cmdargv) - 1 < len(argdesc):
        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')
464
465


466
467
468
469
470
471
def checkarg(cmdargv, *argdesc):
    checkarg_atleast(cmdargv, *argdesc)
    checkarg_atmost(cmdargv, *argdesc)


def serve(action, cmdargv, user, privileged, remote_addr):
472
473
    if enable_maintenance:
        if remote_addr not in maintenance_exc:
474
            raise aurweb.exceptions.MaintenanceException
475
476
    if bans_match(remote_addr):
        raise aurweb.exceptions.BannedException
477
    log_ssh_login(user, remote_addr)
478

479
480
481
482
    if action == 'git' and cmdargv[1] in ('upload-pack', 'receive-pack'):
        action = action + '-' + cmdargv[1]
        del cmdargv[1]

483
    if action == 'git-upload-pack' or action == 'git-receive-pack':
484
        checkarg(cmdargv, 'path')
485
486
487
488
489
490
491
492

        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):
493
            raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase)
494
495
496

        if action == 'git-receive-pack' and pkgbase_exists(pkgbase):
            if not privileged and not pkgbase_has_write_access(pkgbase, user):
497
                raise aurweb.exceptions.PermissionDeniedException(user)
498
499
500
501
502
503
504

        os.environ["AUR_USER"] = user
        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':
505
        checkarg(cmdargv, 'repository name')
506
507
        pkgbase_set_keywords(cmdargv[1], cmdargv[2:])
    elif action == 'list-repos':
508
        checkarg(cmdargv)
509
510
        list_repos(user)
    elif action == 'setup-repo':
511
        checkarg(cmdargv, 'repository name')
512
513
514
515
        warn('{:s} is deprecated. '
             'Use `git push` to create new repositories.'.format(action))
        create_pkgbase(cmdargv[1], user)
    elif action == 'restore':
516
        checkarg(cmdargv, 'repository name')
517
518
519
520
521
522
523
524

        pkgbase = cmdargv[1]
        create_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':
525
        checkarg(cmdargv, 'repository name')
526
527
528
529

        pkgbase = cmdargv[1]
        pkgbase_adopt(pkgbase, user, privileged)
    elif action == 'disown':
530
        checkarg(cmdargv, 'repository name')
531
532
533

        pkgbase = cmdargv[1]
        pkgbase_disown(pkgbase, user, privileged)
534
    elif action == 'flag':
535
        checkarg(cmdargv, 'repository name', 'comment')
536
537
538
539
540

        pkgbase = cmdargv[1]
        comment = cmdargv[2]
        pkgbase_flag(pkgbase, user, comment)
    elif action == 'unflag':
541
        checkarg(cmdargv, 'repository name')
542
543
544

        pkgbase = cmdargv[1]
        pkgbase_unflag(pkgbase, user)
545
546
547
548
549
550
551
552
553
554
    elif action == 'vote':
        checkarg(cmdargv, 'repository name')

        pkgbase = cmdargv[1]
        pkgbase_vote(pkgbase, user)
    elif action == 'unvote':
        checkarg(cmdargv, 'repository name')

        pkgbase = cmdargv[1]
        pkgbase_unvote(pkgbase, user)
555
    elif action == 'set-comaintainers':
556
        checkarg_atleast(cmdargv, 'repository name')
557
558
559
560
561
562
563
564

        pkgbase = cmdargv[1]
        userlist = cmdargv[2:]
        pkgbase_set_comaintainers(pkgbase, userlist, user, privileged)
    elif action == 'help':
        cmds = {
            "adopt <name>": "Adopt a package base.",
            "disown <name>": "Disown a package base.",
565
            "flag <name> <comment>": "Flag a package base out-of-date.",
566
567
568
569
570
571
            "help": "Show this help message and exit.",
            "list-repos": "List all your repositories.",
            "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).",
572
            "unflag <name>": "Remove out-of-date flag from a package base.",
573
574
            "unvote <name>": "Remove vote from a package base.",
            "vote <name>": "Vote for a package base.",
575
576
577
578
579
            "git-receive-pack": "Internal command used with Git.",
            "git-upload-pack": "Internal command used with Git.",
        }
        usage(cmds)
    else:
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
        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')

    if not ssh_cmd:
        die_with_help("Interactive shell is disabled.")
    cmdargv = shlex.split(ssh_cmd)
    action = cmdargv[0]
    remote_addr = ssh_client.split(' ')[0] if ssh_client else None

    try:
        serve(action, cmdargv, user, privileged, remote_addr)
    except aurweb.exceptions.MaintenanceException:
        die("The AUR is down due to maintenance. We will be back soon.")
600
601
    except aurweb.exceptions.BannedException:
        die("The SSH interface is disabled for your IP address.")
602
603
604
605
    except aurweb.exceptions.InvalidArgumentsException as e:
        die_with_help('{:s}: {}'.format(action, e))
    except aurweb.exceptions.AurwebException as e:
        die('{:s}: {}'.format(action, e))
606
607
608
609


if __name__ == '__main__':
    main()