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

« back to all changes in this revision

Viewing changes to ivle/webapp/filesystem/serve/__init__.py

Provide a public serve view. Under /~user/path/to/script. How shiny.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
import ivle.conf
33
33
from ivle.database import User
34
34
from ivle.webapp.base.views import BaseView
35
 
from ivle.webapp.base.plugins import ViewPlugin
 
35
from ivle.webapp.base.plugins import ViewPlugin, PublicViewPlugin
36
36
from ivle.webapp.errors import NotFound, Unauthorized, Forbidden
37
37
 
38
38
class ServeView(BaseView):
56
56
        self.serve(req, owner, jail, path)
57
57
 
58
58
    def serve(self, req, owner, jail, path):
59
 
        serve_file(req, owner, jail, path)
 
59
        self.serve_file(req, owner, jail, path)
 
60
 
 
61
    def authorize(self, req):
 
62
        """Given a request, checks whether req.username is allowed to
 
63
        access req.path. Returns True on authz success, False on failure.
 
64
        """
 
65
        # Private mode authorization: standard (only logged in user can access
 
66
        # their own files, and can access all of them).
 
67
        return studpath.authorize(req, req.user)
 
68
 
 
69
    def serve_file(self, req, owner, jail, path, download=False, files=None):
 
70
        """Serves a file, using one of three possibilities: interpreting it,
 
71
        serving it directly, or denying it and returning a 403 Forbidden error.
 
72
        No return value. Writes to req (possibly throwing an HTTP error).
 
73
 
 
74
        req: An IVLE request object.
 
75
        owner: The user who owns the file being served.
 
76
        jail: The user's jail.
 
77
        path: Filename in the jail.
 
78
        download:  Should the file be viewed in browser or downloaded
 
79
        """
 
80
 
 
81
        # We need a no-op trampoline run to ensure that the jail is mounted.
 
82
        # Otherwise we won't be able to authorise for public mode!
 
83
        noop_object = interpret.interpreter_objects["noop"]
 
84
        interpret.interpret_file(req, owner, jail, '', noop_object)
 
85
 
 
86
        # Authorize access. If failure, this throws a HTTP_FORBIDDEN error.
 
87
        if not self.authorize(req):
 
88
            raise Unauthorized()
 
89
 
 
90
        args = []
 
91
        if download:
 
92
            args.append('-d')
 
93
 
 
94
        if files and download:
 
95
            args += [os.path.join(path, f) for f in files]
 
96
        else:
 
97
            args.append(path)
 
98
 
 
99
        (out, err) = ivle.interpret.execute_raw(owner, jail, '/home',
 
100
                    os.path.join(ivle.conf.share_path, 'services/serveservice'),
 
101
                    args)
 
102
        assert not err
 
103
 
 
104
        # Remove the JSON from the front of the response, and decode it.
 
105
        json = out.split('\n', 1)[0]
 
106
        out = out[len(json) + 1:]
 
107
        response = cjson.decode(json)
 
108
 
 
109
        if 'error' in response:
 
110
            if response['error'] == 'not-found':
 
111
                raise NotFound()
 
112
            elif response['error'] in ('is-directory', 'forbidden'):
 
113
                raise Forbidden()
 
114
            elif response['error'] == 'is-executable':
 
115
                # We need to execute it. Just run it with Python in the jail.
 
116
                interp_object = interpret.interpreter_objects["cgi-python"]
 
117
                interpret.interpret_file(req, owner, jail, response['path'],
 
118
                                         interp_object, gentle=True)
 
119
                return
 
120
            else:
 
121
                raise AssertionError('Unknown error from serveservice: %s' %
 
122
                                     response['error'])
 
123
 
 
124
        if download:
 
125
            req.headers_out["Content-Disposition"] = \
 
126
                         "attachment; filename=%s" % response['name']
 
127
        req.content_type = response['type']
 
128
        req.write(out)
60
129
 
61
130
class DownloadView(ServeView):
62
131
    def __init__(self, req, path):
68
137
            self.files = None
69
138
 
70
139
    def serve(self, req, owner, jail, path):
71
 
        serve_file(req, owner, jail, path, download=True, files=self.files)
72
 
 
73
 
def authorize(req):
74
 
    """Given a request, checks whether req.username is allowed to
75
 
    access req.path. Returns True on authorization success, False on failure.
76
 
    """
77
 
    # TODO: Reactivate public mode.
78
 
    #if req.publicmode:
 
140
        self.serve_file(req, owner, jail, path, download=True,files=self.files)
 
141
 
 
142
class PublicServeView(ServeView):
 
143
    def __init__(self, req, path):
 
144
        req.path = path
 
145
        super(PublicServeView, self).__init__(req, path)
 
146
 
 
147
    def authorize(self, req):
79
148
        # Public mode authorization: any user can access any other user's
80
 
        # files, BUT the accessed file needs to have its "ivle:published" flag
81
 
        # turned on in the SVN status.
82
 
    #    studpath.authorize_public(req)
83
 
 
84
 
    # Private mode authorization: standard (only logged in user can access
85
 
    # their own files, and can access all of them).
86
 
    return studpath.authorize(req, req.user)
87
 
 
88
 
def serve_file(req, owner, jail, path, download=False, files=None):
89
 
    """Serves a file, using one of three possibilities: interpreting the file,
90
 
    serving it directly, or denying it and returning a 403 Forbidden error.
91
 
    No return value. Writes to req (possibly throwing a server error exception
92
 
    using req.throw_error).
93
 
 
94
 
    req: An IVLE request object.
95
 
    owner: The user who owns the file being served.
96
 
    jail: The user's jail.
97
 
    path: Filename in the jail.
98
 
    download:  Should the file be viewed in browser or downloaded
99
 
    """
100
 
 
101
 
    # We need a no-op trampoline run to ensure that the jail is mounted.
102
 
    # Otherwise we won't be able to authorise for public mode!
103
 
    noop_object = interpret.interpreter_objects["noop"]
104
 
    interpret.interpret_file(req, owner, jail, '', noop_object)
105
 
 
106
 
    # Authorize access. If failure, this throws a HTTP_FORBIDDEN error.
107
 
    if not authorize(req):
108
 
        raise Unauthorized()
109
 
 
110
 
    args = []
111
 
    if download:
112
 
        args.append('-d')
113
 
 
114
 
    if files and download:
115
 
        args += [os.path.join(path, f) for f in files]
116
 
    else:
117
 
        args.append(path)
118
 
 
119
 
    (out, err) = ivle.interpret.execute_raw(req.user, jail, '/home',
120
 
                os.path.join(ivle.conf.share_path, 'services/serveservice'),
121
 
                args)
122
 
    assert not err
123
 
 
124
 
    # Remove the JSON from the front of the response, and decode it.
125
 
    json = out.split('\n', 1)[0]
126
 
    out = out[len(json) + 1:]
127
 
    response = cjson.decode(json)
128
 
 
129
 
    if 'error' in response:
130
 
        if response['error'] == 'not-found':
131
 
            raise NotFound()
132
 
        elif response['error'] in ('is-directory', 'forbidden'):
133
 
            raise Forbidden()
134
 
        elif response['error'] == 'is-executable':
135
 
            # We need to execute it. Just run it with Python in the jail.
136
 
            interp_object = interpret.interpreter_objects["cgi-python"]
137
 
            interpret.interpret_file(req, owner, jail, response['path'],
138
 
                                     interp_object, gentle=True)
139
 
            return
140
 
        else:
141
 
            raise AssertionError('Unknown error from serveservice: %s' %
142
 
                                 response['error'])
143
 
 
144
 
    if download:
145
 
        req.headers_out["Content-Disposition"] = \
146
 
                     "attachment; filename=%s" % response['name']
147
 
    req.content_type = response['type']
148
 
    req.write(out)
149
 
 
150
 
class Plugin(ViewPlugin):
 
149
        # files, BUT the accessed file needs to have a file named '.published'
 
150
        # in its parent directory.
 
151
        return studpath.authorize_public(req)
 
152
 
 
153
class Plugin(ViewPlugin, PublicViewPlugin):
151
154
    urls = [
152
155
        ('serve/*path', ServeView),
153
156
        ('download/*path', DownloadView),
154
157
    ]
 
158
 
 
159
    public_urls = [
 
160
        ('~*path', PublicServeView),
 
161
    ]