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

93 by mattgiuca
New directory hierarchy.
1
# IVLE
2
# Copyright (C) 2007-2008 The University of Melbourne
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18
# App: server
19
# Author: Tom Conway, Matt Giuca
20
# Date: 13/12/2007
21
22
# Serves content to the user (acting as a web server for students files).
23
# For most file types we just serve the static file, but
24
# for python files, we evaluate the python script inside
25
# our safe execution environment.
26
130 by mattgiuca
server: Imports os module correctly (needed by serve_file_directly).
27
import os
93 by mattgiuca
New directory hierarchy.
28
1099.3.7 by William Grant
Fix ServeView to use the new serveservice protocol.
29
import cjson
30
1099.3.15 by William Grant
Remove interpretservice, and clean up ivle.webapp.filesystem.serve.
31
from ivle import (studpath, interpret)
1080.1.65 by William Grant
www/apps/server: Don't use ivle.interpret.get_uid() just to check that a user
32
from ivle.database import User
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
33
from ivle.webapp.base.views import BaseView
1099.1.203 by William Grant
Fix PublicServeView authorisation.
34
from ivle.webapp.base.xhtml import XHTMLErrorView
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
35
from ivle.webapp.base.plugins import ViewPlugin, PublicViewPlugin
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
36
from ivle.webapp.errors import NotFound, Unauthorized, Forbidden
1294.2.57 by William Grant
Serve/Download done too.
37
from ivle.webapp import ApplicationRoot
38
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
39
class ServeView(BaseView):
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
40
    subpath_allowed = True
1673 by William Grant
Reject off-site non-GET requests.
41
    offsite_posts_allowed = True
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
42
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
43
    def authorize(self, req):
44
        return req.user is not None
45
46
    def render(self, req):
47
        """Handler for the Server application which serves pages."""
48
        # Get the username of the student whose work we are browsing, and the
49
        # path on the local machine where the file is stored.
1294.2.57 by William Grant
Serve/Download done too.
50
        (login, jail, path) = studpath.url_to_jailpaths(req.config,
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
51
                                                        self.path)
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
52
53
        owner = User.get_by_login(req.store, login)
54
        if not owner:
55
            # There is no user.
56
            raise NotFound()
57
1099.3.11 by William Grant
Implement a DownloadView. It mostly works.
58
        self.serve(req, owner, jail, path)
59
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
60
    @property
61
    def path(self):
62
        return os.path.join(*self.subpath) if self.subpath else ''
63
1099.3.11 by William Grant
Implement a DownloadView. It mostly works.
64
    def serve(self, req, owner, jail, path):
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
65
        self.serve_file(req, owner, jail, path)
66
1099.1.169 by William Grant
Don't shadow the dispatch-called authorize() in ServeView.
67
    def path_authorize(self, req):
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
68
        """Given a request, checks whether req.username is allowed to
69
        access req.path. Returns True on authz success, False on failure.
1099.1.169 by William Grant
Don't shadow the dispatch-called authorize() in ServeView.
70
71
        This can't be done in the usual authorize(), because we rely on the
72
        jail being mounted.
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
73
        """
74
        # Private mode authorization: standard (only logged in user can access
75
        # their own files, and can access all of them).
76
        return studpath.authorize(req, req.user)
77
78
    def serve_file(self, req, owner, jail, path, download=False, files=None):
79
        """Serves a file, using one of three possibilities: interpreting it,
80
        serving it directly, or denying it and returning a 403 Forbidden error.
81
        No return value. Writes to req (possibly throwing an HTTP error).
82
83
        req: An IVLE request object.
84
        owner: The user who owns the file being served.
85
        jail: The user's jail.
86
        path: Filename in the jail.
87
        download:  Should the file be viewed in browser or downloaded
88
        """
89
90
        # We need a no-op trampoline run to ensure that the jail is mounted.
91
        # Otherwise we won't be able to authorise for public mode!
92
        noop_object = interpret.interpreter_objects["noop"]
93
        interpret.interpret_file(req, owner, jail, '', noop_object)
94
95
        # Authorize access. If failure, this throws a HTTP_FORBIDDEN error.
1099.1.169 by William Grant
Don't shadow the dispatch-called authorize() in ServeView.
96
        if not self.path_authorize(req):
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
97
            raise Unauthorized()
98
99
        args = []
100
        if download:
101
            args.append('-d')
102
103
        if files and download:
104
            args += [os.path.join(path, f) for f in files]
105
        else:
106
            args.append(path)
107
1276 by William Grant
Drop ivle.conf usage from ivle.interpret.
108
        (out, err) = interpret.execute_raw(req.config, owner, jail, '/home',
1250 by William Grant
Unbreak serve - it was depending on the old names of a module.
109
                    os.path.join(req.config['paths']['share'],
1224 by William Grant
Remove ivle.conf dependency from ivle.webapp.filesystem.serve.
110
                                 'services/serveservice'),
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
111
                    args)
112
        assert not err
113
114
        # Remove the JSON from the front of the response, and decode it.
115
        json = out.split('\n', 1)[0]
116
        out = out[len(json) + 1:]
117
        response = cjson.decode(json)
118
119
        if 'error' in response:
120
            if response['error'] == 'not-found':
121
                raise NotFound()
122
            elif response['error'] in ('is-directory', 'forbidden'):
123
                raise Forbidden()
124
            elif response['error'] == 'is-executable':
125
                # We need to execute it. Just run it with Python in the jail.
126
                interp_object = interpret.interpreter_objects["cgi-python"]
127
                interpret.interpret_file(req, owner, jail, response['path'],
128
                                         interp_object, gentle=True)
129
                return
130
            else:
131
                raise AssertionError('Unknown error from serveservice: %s' %
132
                                     response['error'])
133
134
        if download:
1649 by Matt Giuca
serveservice and serve: Fixed download of non-ASCII-named files, by decoding filenames in serveservice (so they aren't mangled by JSON) and re-encoding them in the response headers (as you can't put unicode strings in the HTTP response). This is, as far as I can tell, the last outstanding non-ASCII filenames bug in IVLE, so I am closing bug #523500. Hooray.
135
            req.headers_out["Content-Disposition"] = (
136
                         "attachment; filename=%s" %
137
                             response['name'].encode('utf-8'))
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
138
        req.content_type = response['type']
139
        req.write(out)
93 by mattgiuca
New directory hierarchy.
140
1099.3.11 by William Grant
Implement a DownloadView. It mostly works.
141
class DownloadView(ServeView):
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
142
    def __init__(self, req, context, subpath=None):
143
        super(DownloadView, self).__init__(req, context, subpath)
1099.3.12 by William Grant
Support downloading of a selection of files as a zip.
144
        filelist = req.get_fieldstorage().getlist('path')
145
        if filelist:
146
            self.files = [f.value for f in filelist]
147
        else:
148
            self.files = None
149
1099.3.11 by William Grant
Implement a DownloadView. It mostly works.
150
    def serve(self, req, owner, jail, path):
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
151
        self.serve_file(req, owner, jail, path, download=True,files=self.files)
152
153
class PublicServeView(ServeView):
1294.2.139 by William Grant
Revive PublicServeView.
154
    def __init__(self, req, context, subpath=None):
155
        # XXX: Prepend the username to the path, since the authorization
156
        # code expects that, but req.path drops the first path segment
157
        # for historical reasons.
158
        req.path = os.path.join(context.login, req.path)
159
        super(PublicServeView, self).__init__(req, context, subpath)
160
161
    @property
162
    def path(self):
163
        # XXX: Prepend the username again. See above for explanation.
164
        return os.path.join(
165
            self.context.login, super(PublicServeView, self).path)
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
166
167
    def authorize(self, req):
1099.1.203 by William Grant
Fix PublicServeView authorisation.
168
        # Only accessible in public mode.
169
        return req.user is None
170
171
    def path_authorize(self, req):
262 by mattgiuca
studpath: Added "authorize" function which checks the logged in user against
172
        # Public mode authorization: any user can access any other user's
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
173
        # files, BUT the accessed file needs to have a file named '.published'
174
        # in its parent directory.
175
        return studpath.authorize_public(req)
176
177
class Plugin(ViewPlugin, PublicViewPlugin):
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
178
    views = [(ApplicationRoot, 'serve', ServeView),
179
             (ApplicationRoot, 'download', DownloadView)
1294.2.57 by William Grant
Serve/Download done too.
180
             ]
181
1294.2.139 by William Grant
Revive PublicServeView.
182
    public_views = [(User, None, PublicServeView)]