~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
1801.1.1 by William Grant
Replace cjson with json, or simplejson if json is not available (Python <2.6)
29
try:
30
    import json
31
except ImportError:
32
    import simplejson as json
1099.3.7 by William Grant
Fix ServeView to use the new serveservice protocol.
33
1099.3.15 by William Grant
Remove interpretservice, and clean up ivle.webapp.filesystem.serve.
34
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
35
from ivle.database import User
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
36
from ivle.webapp.base.views import BaseView
1099.1.203 by William Grant
Fix PublicServeView authorisation.
37
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.
38
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.
39
from ivle.webapp.errors import NotFound, Unauthorized, Forbidden
1294.2.57 by William Grant
Serve/Download done too.
40
from ivle.webapp import ApplicationRoot
41
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
42
class ServeView(BaseView):
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
43
    subpath_allowed = True
1673 by William Grant
Reject off-site non-GET requests.
44
    offsite_posts_allowed = True
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
45
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
46
    def authorize(self, req):
47
        return req.user is not None
48
49
    def render(self, req):
50
        """Handler for the Server application which serves pages."""
51
        # Get the username of the student whose work we are browsing, and the
52
        # path on the local machine where the file is stored.
1294.2.57 by William Grant
Serve/Download done too.
53
        (login, jail, path) = studpath.url_to_jailpaths(req.config,
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
54
                                                        self.path)
1099.3.6 by William Grant
Move serve over to the new framework. It sort of works, except not.
55
56
        owner = User.get_by_login(req.store, login)
57
        if not owner:
58
            # There is no user.
59
            raise NotFound()
60
1099.3.11 by William Grant
Implement a DownloadView. It mostly works.
61
        self.serve(req, owner, jail, path)
62
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
63
    @property
64
    def path(self):
65
        return os.path.join(*self.subpath) if self.subpath else ''
66
1099.3.11 by William Grant
Implement a DownloadView. It mostly works.
67
    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.
68
        self.serve_file(req, owner, jail, path)
69
1099.1.169 by William Grant
Don't shadow the dispatch-called authorize() in ServeView.
70
    def path_authorize(self, req):
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
71
        """Given a request, checks whether req.username is allowed to
72
        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.
73
74
        This can't be done in the usual authorize(), because we rely on the
75
        jail being mounted.
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
76
        """
77
        # Private mode authorization: standard (only logged in user can access
78
        # their own files, and can access all of them).
79
        return studpath.authorize(req, req.user)
80
81
    def serve_file(self, req, owner, jail, path, download=False, files=None):
82
        """Serves a file, using one of three possibilities: interpreting it,
83
        serving it directly, or denying it and returning a 403 Forbidden error.
84
        No return value. Writes to req (possibly throwing an HTTP error).
85
86
        req: An IVLE request object.
87
        owner: The user who owns the file being served.
88
        jail: The user's jail.
89
        path: Filename in the jail.
90
        download:  Should the file be viewed in browser or downloaded
91
        """
92
93
        # We need a no-op trampoline run to ensure that the jail is mounted.
94
        # Otherwise we won't be able to authorise for public mode!
95
        noop_object = interpret.interpreter_objects["noop"]
96
        interpret.interpret_file(req, owner, jail, '', noop_object)
97
98
        # 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.
99
        if not self.path_authorize(req):
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
100
            raise Unauthorized()
101
102
        args = []
103
        if download:
104
            args.append('-d')
105
106
        if files and download:
107
            args += [os.path.join(path, f) for f in files]
108
        else:
109
            args.append(path)
110
1276 by William Grant
Drop ivle.conf usage from ivle.interpret.
111
        (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.
112
                    os.path.join(req.config['paths']['share'],
1224 by William Grant
Remove ivle.conf dependency from ivle.webapp.filesystem.serve.
113
                                 'services/serveservice'),
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
114
                    args)
115
        assert not err
116
117
        # Remove the JSON from the front of the response, and decode it.
1801.1.1 by William Grant
Replace cjson with json, or simplejson if json is not available (Python <2.6)
118
        j = out.split('\n', 1)[0]
119
        out = out[len(j) + 1:]
120
        response = json.loads(j)
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
121
122
        if 'error' in response:
123
            if response['error'] == 'not-found':
124
                raise NotFound()
125
            elif response['error'] in ('is-directory', 'forbidden'):
126
                raise Forbidden()
127
            elif response['error'] == 'is-executable':
128
                # We need to execute it. Just run it with Python in the jail.
129
                interp_object = interpret.interpreter_objects["cgi-python"]
130
                interpret.interpret_file(req, owner, jail, response['path'],
131
                                         interp_object, gentle=True)
132
                return
133
            else:
134
                raise AssertionError('Unknown error from serveservice: %s' %
135
                                     response['error'])
136
137
        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.
138
            req.headers_out["Content-Disposition"] = (
139
                         "attachment; filename=%s" %
140
                             response['name'].encode('utf-8'))
1827 by William Grant
Encode content_type when downloading files. cjson made us write bad code.
141
        req.content_type = response['type'].encode('utf-8')
1791.2.4 by David Coles
Serve: Set Content-Length when serving files or zip archives
142
        req.content_length = response.get('size')
1099.1.147 by William Grant
Provide a public serve view. Under /~user/path/to/script. How shiny.
143
        req.write(out)
93 by mattgiuca
New directory hierarchy.
144
1099.3.11 by William Grant
Implement a DownloadView. It mostly works.
145
class DownloadView(ServeView):
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
146
    def __init__(self, req, context, subpath=None):
147
        super(DownloadView, self).__init__(req, context, subpath)
1099.3.12 by William Grant
Support downloading of a selection of files as a zip.
148
        filelist = req.get_fieldstorage().getlist('path')
149
        if filelist:
150
            self.files = [f.value for f in filelist]
151
        else:
152
            self.files = None
153
1099.3.11 by William Grant
Implement a DownloadView. It mostly works.
154
    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.
155
        self.serve_file(req, owner, jail, path, download=True,files=self.files)
156
157
class PublicServeView(ServeView):
1294.2.139 by William Grant
Revive PublicServeView.
158
    def __init__(self, req, context, subpath=None):
159
        # XXX: Prepend the username to the path, since the authorization
160
        # code expects that, but req.path drops the first path segment
161
        # for historical reasons.
162
        req.path = os.path.join(context.login, req.path)
163
        super(PublicServeView, self).__init__(req, context, subpath)
164
165
    @property
166
    def path(self):
167
        # XXX: Prepend the username again. See above for explanation.
168
        return os.path.join(
169
            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.
170
171
    def authorize(self, req):
1099.1.203 by William Grant
Fix PublicServeView authorisation.
172
        # Only accessible in public mode.
173
        return req.user is None
174
175
    def path_authorize(self, req):
262 by mattgiuca
studpath: Added "authorize" function which checks the logged in user against
176
        # 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.
177
        # files, BUT the accessed file needs to have a file named '.published'
178
        # in its parent directory.
179
        return studpath.authorize_public(req)
180
181
class Plugin(ViewPlugin, PublicViewPlugin):
1294.2.60 by William Grant
Move the already-ported filesystem views to use subpaths.
182
    views = [(ApplicationRoot, 'serve', ServeView),
183
             (ApplicationRoot, 'download', DownloadView)
1294.2.57 by William Grant
Serve/Download done too.
184
             ]
185
1294.2.139 by William Grant
Revive PublicServeView.
186
    public_views = [(User, None, PublicServeView)]