diff options
author | Justin Lewis <jtl1728@rit.edu> | 2010-01-11 22:38:48 (GMT) |
---|---|---|
committer | Justin Lewis <jtl1728@rit.edu> | 2010-01-11 22:42:14 (GMT) |
commit | 537cb64fa14b682bea94d949ee6b4db7866c6631 (patch) | |
tree | a51e015898a8f2a8a8a2c4548a9530d1c882737a | |
parent | 6372bc63a14c01a5d5fa7f1d5bf4d990a2f17700 (diff) |
Basic permissions: download only, add/remove, admin.
The first user to connect to the server is added as an admin. Admins
will get a "Server Settings" button on their UI. When clicked, they
will be presented with a list of all users ever connected to the server.
There they can give them upload/remove and admin privileges if desired.
-rw-r--r-- | FileShare.activity/FileShareActivity.py | 56 | ||||
-rw-r--r-- | FileShare.activity/GuiView.py | 78 | ||||
-rw-r--r-- | FileShare.server/server.py | 154 | ||||
-rw-r--r-- | FileShare.server/shared_files/__file_data.json (copied from FileShare.server/shared_files/__json_data.json) | 0 | ||||
-rw-r--r-- | FileShare.server/shared_files/__user_data.json (renamed from FileShare.server/shared_files/__json_data.json) | 0 |
5 files changed, 256 insertions, 32 deletions
diff --git a/FileShare.activity/FileShareActivity.py b/FileShare.activity/FileShareActivity.py index cd1eb70..dd83102 100644 --- a/FileShare.activity/FileShareActivity.py +++ b/FileShare.activity/FileShareActivity.py @@ -24,6 +24,7 @@ import journalentrybundle import dbus import gobject import zipfile +from hashlib import sha1 from gettext import gettext as _ from sugar.activity.activity import Activity, ActivityToolbox @@ -101,6 +102,10 @@ class FileShareActivity(Activity): self._mode = "P2P" prof = profile.get_profile() + self._user_key_hash = sha1(prof.pubkey).hexdigest() + self._user_nick = profile.get_nick_name() + self._user_permissions = 0 + jabber_serv = None #Need to check if on 82 or higher if hasattr(prof, 'jabber_server'): @@ -114,6 +119,7 @@ class FileShareActivity(Activity): if jabber_serv: self.server_ip = jabber_serv self.server_port= 14623 + self.s_version = 0 if self.isServer and self.check_for_server() and self._server_mode(): self._mode = "SERVER" @@ -156,12 +162,50 @@ class FileShareActivity(Activity): if r1.status == 200: s_version= r1.read() conn.close() - return s_version + + if int(s_version) >= 2: + # Version 2 supports permissions, announce user so server + # can cache user info and be added to the access list if allowed + + params = { 'id': self._user_key_hash, + 'nick': self._user_nick + } + try: + opener = urllib2.build_opener( MultipartPostHandler.MultipartPostHandler) + f = opener.open("http://%s:%d/announce_user"%(self.server_ip, self.server_port), params) + self._user_permissions = int(f.read()) + except: + raise ServerRequestFailure + + else: + # Older version didn't have permissions, set 1 as default (upload/remove) + self._user_permissions = 1 + self.s_version = s_version + return True else: return False except: return False + def get_server_user_list(self): + params = { 'id': self._user_key_hash } + try: + opener = urllib2.build_opener( MultipartPostHandler.MultipartPostHandler) + f = opener.open("http://%s:%d/user_list"%(self.server_ip, self.server_port), params) + return simplejson.loads(f.read()) + except: + raise ServerRequestFailure + + def change_server_user(self, userId, level): + params = { 'id': self._user_key_hash, + 'userid': userId, + 'level': level + } + try: + opener = urllib2.build_opener( MultipartPostHandler.MultipartPostHandler) + f = opener.open("http://%s:%d/user_mod"%(self.server_ip, self.server_port), params) + except: + raise ServerRequestFailure def build_file(self, jobject): #If object has activity id and it is filled in, use that as hash @@ -209,6 +253,10 @@ class FileShareActivity(Activity): params = { 'jdata': simplejson.dumps(file_info.share_dump()), 'file': open(bundle_path, 'rb') } + + if self.s_version >= 2: + params['id'] = self._user_key_hash + try: opener = urllib2.build_opener( MultipartPostHandler.MultipartPostHandler) opener.open("http://%s:%d/upload"%(self.server_ip, self.server_port), params) @@ -216,7 +264,11 @@ class FileShareActivity(Activity): raise FileUploadFailure() def remove_file_from_server( self, file_id ): - params = { 'id': file_id } + params = { 'fid': file_id } + + if self.s_version >= 2: + params['id'] = self._user_key_hash + try: opener = urllib2.build_opener( MultipartPostHandler.MultipartPostHandler) opener.open("http://%s:%d/remove"%(self.server_ip, self.server_port), params) diff --git a/FileShare.activity/GuiView.py b/FileShare.activity/GuiView.py index ba49b1d..528df49 100644 --- a/FileShare.activity/GuiView.py +++ b/FileShare.activity/GuiView.py @@ -188,6 +188,77 @@ class GuiHandler(): def _alert_cancel_cb(self, alert, response_id): self.activity.remove_alert(alert) + def showAdmin(self, widget, data=None): + def call(): + try: + userList = self.activity.get_server_user_list() + + except ServerRequestFailure: + self._alert(_("Failed to get user list from server")) + self.show_throbber( False ) + else: + level = [_("Download Only"), _("Upload/Remove"), _("Admin")] + + myTable = gtk.Table(10, 1, False) + hbbox = gtk.HButtonBox() + returnBut = gtk.Button(_("Return to Main Screen")) + returnBut.connect("clicked",self.restore_view, None) + hbbox.add(returnBut) + + listbox = gtk.VBox() + + for key in userList: + holder = gtk.HBox() + label = gtk.Label(userList[key][0]) + label.set_alignment(0, 0) + holder.pack_start(label) + + if key == self.activity._user_key_hash: + mode_box = gtk.Label(level[userList[key][1]]) + mode_box.set_alignment(1,0) + else: + mode_box = gtk.combo_box_new_text() + for option in level: + mode_box.append_text( option ) + + mode_box.set_active(userList[key][1]) + mode_box.connect("changed", self.user_changed, key) + + holder.pack_start(mode_box, False, False, 0) + listbox.pack_start(holder, False, False, 0) + + window = gtk.ScrolledWindow() + window.add_with_viewport(listbox) + + myTable.attach(hbbox,0,1,0,1) + myTable.attach(window,0,1,1,10) + + self.activity.set_canvas(myTable) + self.activity.show_all() + + self.show_throbber(True, _("Please Wait... Requesting user list from server")) + threading.Thread(target=call).start() + + + def user_changed(self, widget, id): + widget.set_sensitive(False) + def change(): + try: + self.activity.change_server_user(id, widget.get_active()) + widget.set_sensitive(True) + except ServerRequestFailure: + parent = widget.get_parent() + parent.remove(widget) + lbl = gtk.Label(_("User Change Failed")) + lbl.set_alignment(1,0) + lbl.show() + parent.add( lbl ) + + threading.Thread(target=change).start() + + def restore_view(self, widget, data = None): + self.show_throbber( False ) + class GuiView(gtk.Table): """ @@ -219,7 +290,7 @@ class GuiView(gtk.Table): hbbox.add(remFileButton) else: - if activity._mode == 'SERVER': + if activity._mode == 'SERVER' and activity._user_permissions != 0: addFileButton = gtk.Button(_("Upload A File")) addFileButton.connect("clicked", self.guiHandler.requestAddFile, {'upload':True}) hbbox.add(addFileButton) @@ -228,7 +299,10 @@ class GuiView(gtk.Table): remFileButton.connect("clicked", self.guiHandler.requestRemFile, {'remove':True}) hbbox.add(remFileButton) - + if activity._user_permissions == 2: + adminButton = gtk.Button(_("Server Settings")) + adminButton.connect("clicked", self.guiHandler.showAdmin, None) + hbbox.add(adminButton) downloadFileButton = gtk.Button(_("Download File")) downloadFileButton.connect("clicked", self.guiHandler.requestDownloadFile, None) diff --git a/FileShare.server/server.py b/FileShare.server/server.py index 231c35e..3cff570 100644 --- a/FileShare.server/server.py +++ b/FileShare.server/server.py @@ -5,7 +5,7 @@ import os import cgi # Version string for future protocol change as well as server verification -s_version = 1 +s_version = 2 port = 14623 class FileManager: @@ -14,6 +14,7 @@ class FileManager: """ def __init__(self, file_path = "shared_files"): self.fileList = {} + self.userList = {} self.file_path = file_path self.load() @@ -22,19 +23,28 @@ class FileManager: Loads file data from __json_data.json if it exists in the file_path """ - settings_path = os.path.join(self.file_path, "__json_data.json") + settings_path = os.path.join(self.file_path, "__file_data.json") if os.path.exists( settings_path ): self.fileList = simplejson.loads( open( settings_path, 'r' ).read() ) + settings_path = os.path.join(self.file_path, "__user_data.json") + if os.path.exists( settings_path ): + self.userList = simplejson.loads( open( settings_path, 'r' ).read() ) + def save(self): """ Saves the current file list into __json_data.json """ - settings_path = os.path.join(self.file_path, "__json_data.json") + settings_path = os.path.join(self.file_path, "__file_data.json") f = open( settings_path, 'w' ) f.write( simplejson.dumps( self.fileList ) ) f.close() + settings_path = os.path.join(self.file_path, "__user_data.json") + f = open( settings_path, 'w' ) + f.write( simplejson.dumps( self.userList ) ) + f.close() + def add_file(self, key, dict, data): """ Adds a file to the file list and saves the file to the file_path @@ -72,6 +82,12 @@ class FileManager: """ return simplejson.dumps(self.fileList) + def get_user_str(self): + """ + Dumps a json string of the user list + """ + return simplejson.dumps(self.userList) + def get_file_contents(self, key): """ Returns the file data based off its key @@ -87,17 +103,53 @@ class FileManager: """ return self.fileList.has_key( key ) + def user_permissions(self, id, nick): + print "GOT USER REQUEST %s (%s)" % (nick, id) + if self.userList.has_key(id) == False: + permission = 0 + if len( self.userList ) == 0: + permission = 2 + self.userList[id] = [nick, permission] + self.save() + + if self.userList[id][0] != nick: + self.userList[id][0] = nick + self.save() + + return self.userList[id][1] + + def change_user_permissions(self, id, level): + if self.userList.has_key(id): + self.userList[id][1] = int(level) + self.save() + + def can_rem(self, id): + return self.userList.has_key(id) and self.userList[id][1] != 0 + + def can_upload(self, id): + return self.userList.has_key(id) and self.userList[id][1] != 0 + + def can_admin(self, id): + return self.userList.has_key(id) and self.userList[id][1] == 2 + class MyServer(BaseHTTPServer.BaseHTTPRequestHandler): """ Simple http server: Pages: - * /, /index.html A page saying that the system is running - * /version Returns server revision number - * /fileList A json string of the file list - * /ANYFILEID Downloads the file if the id matches - * POST /upload Expects an upload jdata and file + GET: + * /, /index.html A page saying that the system is running + * /version Returns server revision number + * /fileList A json string of the file list + * /{ANY_ID} Downloads the file if the id matches + POST: + * /upload Adds file (expects id, jdata and file) + * /remove Removes file (expects id and fid) + * /announce_user Adds user to list (and responds with permission level) + (expects id, nick) + * /user_list Returns user list (expects id, must have admin permission level) + * /user_mod Changes user permissions (expects id (ADMIN), userId, level) """ def do_GET(self): if self.path == "/" or self.path == "/index.html": @@ -147,34 +199,80 @@ class MyServer(BaseHTTPServer.BaseHTTPRequestHandler): }) if self.path == "/upload": - # Begin the response - self.send_response(200) - self.end_headers() + if form.has_key('id') and fileMan.can_upload( form['id'].value ): + # Begin the response + self.send_response(200, 'OK') + self.end_headers() + + if( form.has_key('jdata') and form.has_key('file') ): + try: + data = simplejson.loads( form['jdata'].value ) + file_data = form['file'].file.read() + fileMan.add_file(data[0], data, file_data) + + # Begin the response + self.send_response(200) + self.end_headers() + except: + self.send_error(500,'Server Error or Invalid Request') + self.end_headers() + return + else: + self.send_error(403, "Forbidden") + self.end_headers() + elif self.path == "/remove": + if( form.has_key('id') and fileMan.can_rem( form['id'].value ) ): + self.send_response(200, 'OK') + self.end_headers() + + if( form.has_key('fid') and fileMan.has_file_key( form['fid'].value ) ): + fileMan.rem_file( form['fid'].value ) + else: + self.send_error(403, "Forbidden") + self.end_headers() - if( form.has_key('jdata') and form.has_key('file') ): - try: - data = simplejson.loads( form['jdata'].value ) - file_data = form['file'].file.read() - fileMan.add_file(data[0], data, file_data) + elif self.path == "/announce_user": + if( form.has_key('id') and form.has_key('nick') ): + self.send_response(200, 'OK') + self.end_headers() + self.wfile.write( fileMan.user_permissions(form['id'].value, form['nick'].value) ) + else: + self.send_error(400, 'Bad Request') + self.end_headers() - # Begin the response - self.send_response(200) + elif self.path == "/user_list": + if form.has_key('id'): + if fileMan.can_admin( form['id'].value ): + self.send_response(200, 'OK') self.end_headers() - except: - self.send_error(500,'Server Error or Invalid Request') + self.wfile.write( fileMan.get_user_str() ) + else: + self.send_error(403, "Forbidden") self.end_headers() - return - elif self.path == "/remove": - self.send_response(200) - self.end_headers() - - print form.keys() + else: + self.send_error(400, 'Bad Request') + self.end_headers() - if( form.has_key('id') and fileMan.has_file_key( form['id'].value ) ): - fileMan.rem_file( form['id'].value ) + elif self.path == "/user_mod": + if form.has_key('id') and form.has_key('userid') and form.has_key('level'): + if fileMan.can_admin( form['id'].value ): + if form['id'].value != form['userid'].value: + self.send_response(200, 'OK') + self.end_headers() + fileMan.change_user_permissions(form['userid'].value, form['level'].value) + else: + self.send_error(400, 'Bad Request, Can not modify yourself') + self.end_headers() + else: + self.send_error(403, "Forbidden") + self.end_headers() + else: + self.send_error(400, 'Bad Request') + self.end_headers() else: self.send_error(404,'File Not Found (POST): %s' % self.path) + self.end_headers() diff --git a/FileShare.server/shared_files/__json_data.json b/FileShare.server/shared_files/__file_data.json index 9e26dfe..9e26dfe 100644 --- a/FileShare.server/shared_files/__json_data.json +++ b/FileShare.server/shared_files/__file_data.json diff --git a/FileShare.server/shared_files/__json_data.json b/FileShare.server/shared_files/__user_data.json index 9e26dfe..9e26dfe 100644 --- a/FileShare.server/shared_files/__json_data.json +++ b/FileShare.server/shared_files/__user_data.json |