~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/fileservice_lib/action.py

  • Committer: William Grant
  • Date: 2009-12-02 02:20:57 UTC
  • mto: This revision was merged to the branch mainline in revision 1353.
  • Revision ID: grantw@unimelb.edu.au-20091202022057-m3w3rzrzp47y89to
Refuse to traverse through an object to which the user has no permissions. This stops information leakage in breadcrumbs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
131
131
import os
132
132
import cStringIO
133
133
import shutil
 
134
import urllib
134
135
 
135
136
import pysvn
136
137
 
137
138
from ivle import (util, studpath, zip)
 
139
from ivle.fileservice_lib.exceptions import WillNotOverwrite
138
140
import ivle.conf
139
141
 
 
142
 
140
143
def get_login(_realm, existing_login, _may_save):
141
144
    """Callback function used by pysvn for authentication.
142
145
    realm, existing_login, _may_save: The 3 arguments passed by pysvn to
195
198
    except KeyError:
196
199
        # Default, just send an error but then continue
197
200
        raise ActionError("Unknown action")
198
 
    action(req, fields)
 
201
    return action(req, fields)
199
202
 
200
203
def actionpath_to_urlpath(req, path):
201
204
    """Determines the URL path (relative to the student home) upon which the
226
229
 
227
230
    Does not mutate req.
228
231
    """
229
 
    (_, _, r) = studpath.url_to_jailpaths(actionpath_to_urlpath(req, path))
 
232
    r = studpath.to_home_path(actionpath_to_urlpath(req, path))
230
233
    if r is None:
231
234
        raise ActionError("Invalid path")
232
235
    return r
264
267
    except shutil.Error:
265
268
        raise ActionError("Could not move the file specified")
266
269
 
 
270
def svn_movefile(req, frompath, topath, copy=False):
 
271
    """Performs an svn move, resolving filenames, checking for any errors,
 
272
    and throwing ActionErrors if necessary. Can also be used to do a copy
 
273
    operation instead.
 
274
 
 
275
    frompath and topath are straight paths from the client. Will be checked.
 
276
    """
 
277
    if frompath is None or topath is None:
 
278
        raise ActionError("Required field missing")
 
279
    frompath = actionpath_to_local(req, frompath)
 
280
    topath = actionpath_to_local(req, topath)
 
281
    if not os.path.exists(frompath):
 
282
        raise ActionError("The source file does not exist")
 
283
    if os.path.exists(topath):
 
284
        if frompath == topath:
 
285
            raise ActionError("Source and destination are the same")
 
286
        raise ActionError("A file already exists with that name")
 
287
 
 
288
    try:
 
289
        if copy:
 
290
            svnclient.copy(frompath, topath)
 
291
        else:
 
292
            svnclient.move(frompath, topath)
 
293
    except OSError:
 
294
        raise ActionError("Could not move the file specified")
 
295
    except pysvn.ClientError:
 
296
        raise ActionError("Could not move the file specified")  
 
297
 
 
298
 
267
299
### ACTIONS ###
268
300
 
269
301
def action_delete(req, fields):
371
403
 
372
404
    Reads fields: 'path', 'data' (file upload, multiple), 'unpack'
373
405
    """
374
 
 
375
406
    # Important: Data is "None" if the file submitted is empty.
376
407
    path = fields.getfirst('path')
377
408
    data = fields['data']
390
421
    for datum in data:
391
422
        # Each of the uploaded files
392
423
        filepath = os.path.join(path, datum.filename)
 
424
        filepath_local = studpath.to_home_path(filepath)
 
425
        if os.path.isdir(filepath_local):
 
426
            raise ActionError("A directory already exists "
 
427
                    + "with that name")
 
428
        else:
 
429
            if os.path.exists(filepath_local):
 
430
                raise ActionError("A file already exists with that name")
393
431
        filedata = datum.file
394
432
 
395
433
        if unpack and datum.filename.lower().endswith(".zip"):
399
437
            # filename)
400
438
            try:
401
439
                # First get the entire path (within jail)
402
 
                _, _, abspath = studpath.url_to_jailpaths(path)
 
440
                abspath = studpath.to_home_path(path)
403
441
                abspath = os.path.join(os.sep, abspath)
404
442
                zip.unzip(abspath, filedata)
405
443
            except (OSError, IOError):
406
444
                goterror = True
 
445
            except WillNotOverwrite, e:
 
446
                raise ActionError("File '" + e.filename + "' already exists.")
407
447
        else:
408
448
            # Not a zip file
409
 
            (_, _, filepath_local) = studpath.url_to_jailpaths(filepath)
 
449
            filepath_local = studpath.to_home_path(filepath)
410
450
            if filepath_local is None:
411
451
                raise ActionError("Invalid path")
412
452
 
445
485
    files = fields.getlist('file')
446
486
    if dst is None or src is None or mode is None:
447
487
        raise ActionError("Required field missing")
448
 
    if mode == "copy":
449
 
        copy = True
450
 
    elif mode == "move":
451
 
        copy = False
452
 
    else:
453
 
        raise ActionError("Invalid mode (must be 'copy' or 'move')")
 
488
 
454
489
    dst_local = actionpath_to_local(req, dst)
455
490
    if not os.path.isdir(dst_local):
456
491
        raise ActionError("dst is not a directory")
465
500
        # The destination is found by taking just the basename of the file
466
501
        topath = os.path.join(dst, os.path.basename(file))
467
502
        try:
468
 
            movefile(req, frompath, topath, copy)
 
503
            if mode == "copy":
 
504
                movefile(req, frompath, topath, True)
 
505
            elif mode == "move":
 
506
                movefile(req, frompath, topath, False)
 
507
            elif mode == "svncopy":
 
508
                svn_movefile(req, frompath, topath, True)
 
509
            elif mode == "svnmove":
 
510
                svn_movefile(req, frompath, topath, False)
 
511
            else:
 
512
                raise ActionError("Invalid mode (must be '(svn)copy' or '(svn)move')")
469
513
        except ActionError, message:
470
514
            # Store the error for later; we want to copy as many as possible
471
515
            if errormsg is None:
489
533
    Reads fields: 'path'
490
534
    """
491
535
    paths = fields.getlist('path')
492
 
    user = studpath.url_to_local(req.path)[0]
 
536
    user = util.split_path(req.path)[0]
493
537
    homedir = "/home/%s" % user
494
538
    if len(paths):
495
539
        paths = map(lambda path: actionpath_to_local(req, path), paths)
496
540
    else:
497
 
        paths = [studpath.url_to_jailpaths(req.path)[2]]
 
541
        paths = [studpath.to_home_path(req.path)]
498
542
 
499
543
    # Set all the dirs in home dir world browsable (o+r,o+x)
500
544
    #FIXME: Should really only do those in the direct path not all of the 
524
568
    if len(paths):
525
569
        paths = map(lambda path: actionpath_to_local(req, path), paths)
526
570
    else:
527
 
        paths = [studpath.url_to_jailpaths(req.path)[2]]
 
571
        paths = [studpath.to_home_path(req.path)]
528
572
 
529
573
    try:
530
574
        for path in paths:
621
665
    if len(paths):
622
666
        paths = map(lambda path: actionpath_to_local(req, path), paths)
623
667
    else:
624
 
        paths = [studpath.url_to_jailpaths(req.path)[2]]
 
668
        paths = [studpath.to_home_path(req.path)]
625
669
 
626
670
    try:
627
671
        for path in paths:
670
714
    paths = fields.getlist('path')
671
715
    if len(paths) != 2:
672
716
        raise ActionError("usage: svncheckout url local-path")
673
 
    url = ivle.conf.svn_addr + "/" + paths[0]
 
717
    url = ivle.conf.svn_addr + "/" + urllib.quote(paths[0])
674
718
    local_path = actionpath_to_local(req, str(paths[1]))
675
719
    try:
676
720
        svnclient.callback_get_login = get_login
695
739
def action_svnrepostat(req, fields):
696
740
    """Discovers whether a path exists in a repo under the IVLE SVN root.
697
741
 
 
742
    If it does exist, returns a dict containing its metadata.
 
743
 
698
744
    Reads fields: 'path'
699
745
    """
700
746
    path = fields.getfirst('path')
701
747
    url = ivle.conf.svn_addr + "/" + path
702
 
    svnclient.exception_style = 1 
 
748
    svnclient.exception_style = 1
703
749
 
704
750
    try:
705
751
        svnclient.callback_get_login = get_login
706
 
        svnclient.info2(url)
 
752
        info = svnclient.info2(url,
 
753
            revision=pysvn.Revision(pysvn.opt_revision_kind.head))[0][1]
 
754
        return {'svnrevision': info['rev'].number
 
755
                  if info['rev'] and
 
756
                     info['rev'].kind == pysvn.opt_revision_kind.number
 
757
                  else None}
707
758
    except pysvn.ClientError, e:
708
759
        # Error code 170000 means ENOENT in this revision.
709
760
        if e[1][0][1] == 170000:
710
761
            raise util.IVLEError(404, 'The specified repository path does not exist')
711
762
        else:
712
763
            raise ActionError(str(e[0]))
 
764
            
713
765
 
714
766
# Table of all action functions #
715
767
# Each function has the interface f(req, fields).