tahoe-lafs/windows/confwiz.py
robk-tahoe fc91837f69 update confwiz to include account creation ui
this changes the confwiz so that hitting the 'create account' button, rather than
opening a webbrowser to the register page, instead provides a simple account creation
ui directly, along with changes to the backend (native_client.php) to support that.

also added a 'connecting...' message so the user sees a response when they hit
login or create account, since the getBasedir call can sometimes take up to ~5min
(which is unacceptable for a user product, but this at least somewhat ameliorates
the issue of the ui locking up and not giving the user any feedback while it's
happening)
2008-01-21 15:13:10 -07:00

406 lines
14 KiB
Python

BACKEND_URL = 'https://www-test.allmydata.com/native_client.php'
#REGISTER_PAGE = 'https://www-test.allmydata.com/register'
TAHOESVC_NAME = 'Tahoe'
WINFUSESVC_NAME = 'Allmydata Tahoe SMB'
import os
import sys
#import time
import traceback
import urllib2
from urllib import urlencode
#import webbrowser
import wx
from allmydata.util.assertutil import precondition
from allmydata import uri
import amdicon
class AuthError(Exception):
pass
def unicode_to_utf8(uobj):
assert precondition(isinstance(uobj, unicode))
return uobj.encode('utf-8')
def post(url, args):
argstr = urlencode(args)
conn = urllib2.urlopen(url, argstr)
return conn.read()
def get_root_cap(url, user, passwd):
args = {
'action': 'authenticate',
'email': unicode_to_utf8(user),
'passwd': unicode_to_utf8(passwd),
}
root_cap = post(url, args)
if root_cap == '0':
raise AuthError()
elif not uri.is_uri(root_cap):
raise ValueError('%r is not a URI' % (root_cap,))
else:
return root_cap
def create_account(url, user, passwd, subscribe):
args = {
'action': 'create_account',
'email': unicode_to_utf8(user),
'passwd': unicode_to_utf8(passwd),
'subscribe': subscribe and 'true' or 'false',
}
result_code = post(url, args)
return result_code
def get_introducer_furl(url):
return post(url, { 'action': 'getintroducerfurl' })
def write_config_file(filename, contents):
if sys.platform == 'win32':
from allmydata.windows import registry
basedir = registry.get_base_dir_path()
else:
basedir = os.path.expanduser('~/.tahoe')
path = os.path.join(basedir, filename)
dirname = os.path.dirname(path)
if not os.path.exists(dirname):
os.makedirs(dirname)
iff = file(path, 'wb')
iff.write(contents)
iff.close()
def DisplayTraceback(message):
xc = traceback.format_exception(*sys.exc_info())
wx.MessageBox(u"%s\n (%s)"%(message,''.join(xc)), 'Error')
class ConfWizApp(wx.App):
def __init__(self):
wx.App.__init__(self, 0)
def OnInit(self):
try:
wx.InitAllImageHandlers()
self.login_frame = LoginFrame(self)
self.login_frame.CenterOnScreen()
self.SetTopWindow(self.login_frame)
self.SetExitOnFrameDelete(True)
self.login_frame.Show(True)
return True
except:
DisplayTraceback('config wizard init threw an exception')
def swap_to_register_frame(self):
try:
self.login_frame.Show(False)
self.regiser_frame = RegisterFrame(self)
self.regiser_frame.CenterOnScreen()
self.SetTopWindow(self.regiser_frame)
self.SetExitOnFrameDelete(True)
self.regiser_frame.Show(True)
except:
DisplayTraceback('config wizard threw an exception')
class LoginFrame(wx.Frame):
def __init__(self, app):
title = 'Allmydata Tahoe Config Wizard'
wx.Frame.__init__(self, None, -1, title)
self.app = app
self.SetSizeHints(100, 100, 600, 800)
self.SetIcon(amdicon.getIcon())
self.Bind(wx.EVT_CLOSE, self.close)
background = wx.Panel(self, -1)
background.parent = self
self.login_panel = LoginPanel(background)
self.reg_btn_panel = RegisterButtonPanel(background, app)
sizer = wx.BoxSizer(wx.VERTICAL)
background_sizer = wx.BoxSizer(wx.VERTICAL)
background_sizer.Add(self.login_panel, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 26)
background_sizer.Add(self.reg_btn_panel, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 26)
background.SetSizer(background_sizer)
sizer.Add(background, 0, wx.EXPAND | wx.ALL, 0)
self.SetSizer(sizer)
self.SetAutoLayout(True)
self.Fit()
self.Layout()
def close(self, event):
sys.exit()
class RegisterFrame(wx.Frame):
def __init__(self, app):
title = 'Allmydata Tahoe Config Wizard'
wx.Frame.__init__(self, None, -1, title)
self.app = app
self.SetSizeHints(100, 100, 600, 800)
self.SetIcon(amdicon.getIcon())
self.Bind(wx.EVT_CLOSE, self.close)
background = wx.Panel(self, -1)
background.parent = self
self.register_panel = RegisterPanel(background)
sizer = wx.BoxSizer(wx.VERTICAL)
background_sizer = wx.BoxSizer(wx.VERTICAL)
background_sizer.Add(self.register_panel, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 26)
background.SetSizer(background_sizer)
sizer.Add(background, 0, wx.EXPAND | wx.ALL, 0)
self.SetSizer(sizer)
self.SetAutoLayout(True)
self.Fit()
self.Layout()
def close(self, event):
sys.exit()
class LoginPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.parent = parent
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.user_label = wx.StaticText(self, -1, 'Email')
self.pass_label = wx.StaticText(self, -1, 'Password')
self.user_field = wx.TextCtrl(self, -1, u'', size=(260,-1))
self.pass_field = wx.TextCtrl(self, -1, u'', size=(260,-1), style=wx.TE_PASSWORD)
self.login_button = wx.Button(self, -1, 'Sign In')
self.warning_label = wx.StaticText(self, -1, '')
self.warning_label.SetOwnForegroundColour(wx.RED)
wx.EVT_CHAR(self.user_field, self.on_user_entry)
wx.EVT_CHAR(self.pass_field, self.on_pass_entry)
self.Bind(wx.EVT_BUTTON, self.on_login, self.login_button)
login_sizer = wx.FlexGridSizer(3, 2, 5, 4)
login_sizer.Add(self.user_label, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
login_sizer.Add(self.user_field, 0, wx.EXPAND | wx.ALL, 2)
login_sizer.Add(self.pass_label, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
login_sizer.Add(self.pass_field, 0, wx.EXPAND | wx.ALL, 2)
login_sizer.Add(wx.Size(2,2), 0, wx.ALIGN_RIGHT | wx.ALL, 2)
login_sizer.Add(self.login_button, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
self.sizer.Add(login_sizer, 1, wx.EXPAND | wx.ALL, 2)
self.sizer.Add(self.warning_label, 0, wx.CENTER | wx.ALL, 2)
self.SetSizer(self.sizer)
self.SetAutoLayout(True)
def on_user_entry(self, event):
if event.GetKeyCode() == wx.WXK_RETURN:
self.pass_field.SetFocus()
else:
event.Skip()
def on_pass_entry(self, event):
if event.GetKeyCode() == wx.WXK_RETURN:
self.on_login(event)
else:
event.Skip()
def on_login(self, event):
user = self.user_field.GetValue()
passwd = self.pass_field.GetValue()
self.warning_label.SetLabel('Connecting...')
self.Layout()
wx.Yield()
if passwd == '':
self.warning_label.SetLabel('You must enter a password')
self.pass_field.SetFocus()
self.Layout()
return
try:
root_cap = get_root_cap(BACKEND_URL, user, passwd)
write_config_file('private/root_dir.cap', root_cap+'\n')
except AuthError:
self.warning_label.SetLabel('Your email and/or password is incorrect')
self.user_field.SetFocus()
self.Layout()
return
# fetch the introducer furl
ifurl = get_introducer_furl(BACKEND_URL)
write_config_file('introducer.furl', ifurl+'\n')
# start service etc.
if sys.platform == 'win32':
self.start_windows_service(TAHOESVC_NAME)
self.start_windows_service(WINFUSESVC_NAME)
# exit
self.parent.parent.Close()
def start_windows_service(self, svc_name):
try:
import win32service
import win32serviceutil as wsu
if wsu.QueryServiceStatus(svc_name)[1] != win32service.SERVICE_RUNNING:
wsu.StartService(svc_name)
except:
DisplayTraceback('Failed to start windows service "%s"' % (svc_name,))
class RegisterButtonPanel(wx.Panel):
def __init__(self, parent, app):
wx.Panel.__init__(self, parent, -1)
self.parent = parent
self.app = app
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.reg_label = wx.StaticText(self, -1, "Don't have an account?")
self.reg_button = wx.Button(self, -1, 'Create Account')
self.Bind(wx.EVT_BUTTON, self.on_reg_button, self.reg_button)
reg_sizer = wx.FlexGridSizer(1, 2, 5, 4)
reg_sizer.Add(self.reg_label, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
reg_sizer.Add(self.reg_button, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
self.sizer.Add(reg_sizer, 1, wx.EXPAND | wx.ALL, 2)
self.SetSizer(self.sizer)
self.SetAutoLayout(True)
def on_reg_button(self, event):
#webbrowser.open(REGISTER_PAGE)
self.app.swap_to_register_frame()
class RegisterPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.parent = parent
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.user_label = wx.StaticText(self, -1, 'Email')
self.pass_label = wx.StaticText(self, -1, 'Password')
self.conf_label = wx.StaticText(self, -1, 'Confirm Password')
self.user_field = wx.TextCtrl(self, -1, u'', size=(260,-1))
self.pass_field = wx.TextCtrl(self, -1, u'', size=(260,-1), style=wx.TE_PASSWORD)
self.conf_field = wx.TextCtrl(self, -1, u'', size=(260,-1), style=wx.TE_PASSWORD)
self.create_account_button = wx.Button(self, -1, 'Create Account')
self.subscribe_box = wx.CheckBox(self, -1, 'Sign up for our Newsletter')
self.subscribe_box.SetValue(True)
self.warning_label = wx.StaticText(self, -1, '')
self.warning_label.SetOwnForegroundColour(wx.RED)
wx.EVT_CHAR(self.user_field, self.on_user_entry)
wx.EVT_CHAR(self.pass_field, self.on_pass_entry)
wx.EVT_CHAR(self.conf_field, self.on_conf_entry)
self.Bind(wx.EVT_BUTTON, self.on_create_account, self.create_account_button)
login_sizer = wx.FlexGridSizer(4, 2, 5, 4)
login_sizer.Add(self.user_label, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
login_sizer.Add(self.user_field, 0, wx.EXPAND | wx.ALL, 2)
login_sizer.Add(self.pass_label, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
login_sizer.Add(self.pass_field, 0, wx.EXPAND | wx.ALL, 2)
login_sizer.Add(self.conf_label, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
login_sizer.Add(self.conf_field, 0, wx.EXPAND | wx.ALL, 2)
login_sizer.Add(wx.Size(2,2), 0, wx.ALIGN_RIGHT | wx.ALL, 2)
login_sizer.Add(self.create_account_button, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
self.sizer.Add(login_sizer, 1, wx.EXPAND | wx.ALL, 2)
self.sizer.Add(self.warning_label, 0, wx.CENTER | wx.ALL, 2)
self.sizer.Add(self.subscribe_box, 0, wx.CENTER | wx.ALL, 2)
self.SetSizer(self.sizer)
self.SetAutoLayout(True)
def on_user_entry(self, event):
if event.GetKeyCode() == wx.WXK_RETURN:
self.pass_field.SetFocus()
else:
event.Skip()
def on_pass_entry(self, event):
if event.GetKeyCode() == wx.WXK_RETURN:
self.conf_field.SetFocus()
else:
event.Skip()
def on_conf_entry(self, event):
if event.GetKeyCode() == wx.WXK_RETURN:
self.on_create_account(event)
else:
event.Skip()
def on_create_account(self, event):
user = self.user_field.GetValue()
passwd = self.pass_field.GetValue()
pconf = self.conf_field.GetValue()
subscribe = self.subscribe_box.IsChecked()
self.warning_label.SetLabel('Connecting...')
self.Layout()
wx.Yield()
if passwd == '':
self.warning_label.SetLabel('You must enter a password')
self.pass_field.SetFocus()
self.Layout()
return
if passwd != pconf:
self.warning_label.SetLabel("Passwords don't match")
self.pass_field.SetValue('')
self.conf_field.SetValue('')
self.pass_field.SetFocus()
self.Layout()
return
#print 'calling create_account', time.asctime()
result_code = create_account(BACKEND_URL, user, passwd, subscribe)
if result_code == 'account_exists':
# try and log into it; if valid, use it anyway
try:
#print 'calling get_root_cap (ae)', time.asctime()
root_cap = get_root_cap(BACKEND_URL, user, passwd)
write_config_file('private/root_dir.cap', root_cap+'\n')
except AuthError:
self.warning_label.SetLabel('That email address is already registered')
self.user_field.SetFocus()
self.Layout()
return
elif result_code == 'error':
self.warning_label.SetLabel('an error occurred')
self.user_field.SetFocus()
self.Layout()
return
elif result_code == 'ok':
#print 'calling get_root_cap (ok)', time.asctime()
root_cap = get_root_cap(BACKEND_URL, user, passwd)
write_config_file('private/root_dir.cap', root_cap+'\n')
else:
self.warning_label.SetLabel('an unexpected error occurred ("%s")' % (result_code,))
self.user_field.SetFocus()
self.Layout()
return
# fetch the introducer furl
#print 'calling get_introducer_furl', time.asctime()
ifurl = get_introducer_furl(BACKEND_URL)
write_config_file('introducer.furl', ifurl+'\n')
# start service etc.
if sys.platform == 'win32':
self.start_windows_service(TAHOESVC_NAME)
self.start_windows_service(WINFUSESVC_NAME)
# exit
self.parent.parent.Close()
def start_windows_service(self, svc_name):
try:
import win32service
import win32serviceutil as wsu
if wsu.QueryServiceStatus(svc_name)[1] != win32service.SERVICE_RUNNING:
wsu.StartService(svc_name)
except:
DisplayTraceback('Failed to start windows service "%s"' % (svc_name,))
def main():
app = ConfWizApp()
app.MainLoop()
if __name__ == '__main__':
main()