- Big catchup commit to make sure we are up to beta7.

This includes a number of single patches, ranging from the vista fix with the buffers, to the start of many new minor features.
This commit is contained in:
Cas Cremers
2007-05-18 14:06:29 +02:00
parent 5882548643
commit 1542d65def
35 changed files with 538 additions and 204 deletions

View File

@@ -11,6 +11,8 @@ import os.path
""" Import scyther-gui components """
import Scyther
#---------------------------------------------------------------------------
""" Globals """
@@ -19,9 +21,17 @@ basedir = ""
#---------------------------------------------------------------------------
def setBaseDir(mybasedir):
global basedir
basedir = mybasedir
#---------------------------------------------------------------------------
class AboutScyther(wx.Dialog):
def __init__(self,parent,mybasedir=None):
from Version import SCYTHER_GUI_VERSION
global basedir
self.text = '''
@@ -29,6 +39,7 @@ class AboutScyther(wx.Dialog):
<body bgcolor="#ffffff">
<img src="$SPLASH">
<p align="right"><b>Scyther : $VERSION</b></p>
<small>
<p>
<b>Scyther</b> is an automatic tool for the verification and
falsification of security protocols.
@@ -42,21 +53,31 @@ class AboutScyther(wx.Dialog):
<a target="_blank" href="http://people.inf.ethz.ch/cremersc/scyther/index.html">
http://people.inf.ethz.ch/cremersc/scyther/index.html</a>
</p>
<p>
$DETAILS
</p>
<p>
Credits: Cas Cremers (Scyther theory, backend, and main GUI
code), Gijs Hollestelle (Python parser for Scyther XML output).
</p>
</small>
'''
if mybasedir:
basedir = mybasedir
# Debugging output of some parameters
splashdir = os.path.join(basedir,"Images")
splashimage = os.path.join(splashdir,"scyther-splash.png")
details_html = "Base directory: %s<br>\n" % (basedir)
details_html += Scyther.Scyther.GetInfo(html=True)
self.text = self.text.replace("$SPLASH",splashimage)
self.text = self.text.replace("$DETAILS",details_html)
# version information
self.text = self.text.replace("$VERSION", "1.0-beta6")
self.text = self.text.replace("$VERSION", SCYTHER_GUI_VERSION)
wx.Dialog.__init__(self, parent, -1, 'About Scyther',
size=(660,620))

View File

@@ -183,6 +183,7 @@ class AttackWindow(wx.Frame):
# Add attacks (possible with tabs)
self.displays=[]
attacks = self.claim.attacks
n = len(attacks)
if n <= 1:
# Just a single window

View File

@@ -71,10 +71,35 @@ class Editor(object):
def __init__(self, parent):
# Empty start
self.SetText("")
self.SetChanged(False)
def SetText(self):
pass
def SetErrors(self,errors):
pass
def GetChanged(self):
"""
Return true if file was changed
"""
return self.savedtext != self.GetText()
def SetChanged(self,nowchanged=False):
"""
Set changed status
"""
if nowchanged:
self.savedtext = ""
else:
self.SetSaved()
def SetSaved(self):
self.savedtext = self.GetText()
def SetOpened(self):
self.SetSaved()
#---------------------------------------------------------------------------
class EditorNormal(Editor):

View File

@@ -20,7 +20,7 @@ import Editor
""" Some constants """
ID_VERIFY = 100
ID_AUTOVERIFY = 101
ID_STATESPACE = 102
ID_CHARACTERIZE = 102
ID_CHECK = 103
#---------------------------------------------------------------------------
@@ -47,7 +47,7 @@ class MainWindow(wx.Frame):
if len(args) > 0:
filename = args[0]
if filename != '' and os.path.isfile(filename):
self.filename = filename
(self.dirname,self.filename) = os.path.split(filename)
self.load = True
Icon.ScytherIcon(self)
@@ -60,7 +60,7 @@ class MainWindow(wx.Frame):
(wx.ACCEL_NORMAL, wx.WXK_F1,
ID_VERIFY),
(wx.ACCEL_NORMAL, wx.WXK_F2,
ID_STATESPACE),
ID_CHARACTERIZE),
(wx.ACCEL_NORMAL, wx.WXK_F5,
ID_CHECK),
(wx.ACCEL_NORMAL, wx.WXK_F6,
@@ -85,9 +85,9 @@ class MainWindow(wx.Frame):
#bt = wx.Button(self,ID_VERIFY)
#buttons.Add(bt,0)
#self.Bind(wx.EVT_BUTTON, self.OnVerify, bt)
#bt = wx.Button(self,ID_STATESPACE)
#bt = wx.Button(self,ID_CHARACTERIZE)
#buttons.Add(bt,0)
#self.Bind(wx.EVT_BUTTON, self.OnStatespace, bt)
#self.Bind(wx.EVT_BUTTON, self.OnCharacterize, bt)
#sizer.Add(buttons, 0, wx.ALIGN_LEFT)
# Top: input
@@ -98,8 +98,11 @@ class MainWindow(wx.Frame):
if self.load:
textfile = open(os.path.join(self.dirname, self.filename), 'r')
self.editor.SetText(textfile.read())
os.chdir(self.dirname)
if self.dirname != "":
os.chdir(self.dirname)
textfile.close()
self.editor.SetOpened()
self.top.AddPage(self.editor.control,"Protocol description")
self.settings = Settingswindow.SettingsWindow(self.top,self)
self.top.AddPage(self.settings,"Settings")
@@ -138,8 +141,8 @@ class MainWindow(wx.Frame):
self.CreateMenu(menuBar, '&Verify',
[(ID_VERIFY, '&Verify protocol\tF1','Verify the protocol in the buffer using Scyther',
self.OnVerify) ,
(ID_STATESPACE, 'Generate &statespace\tF2','TODO' ,
self.OnStatespace) ,
(ID_CHARACTERIZE, '&Characterize roles\tF2','TODO' ,
self.OnCharacterize) ,
(None, None, None, None),
### Disabled for now (given that it is not reliable enough yet)
#(ID_CHECK, '&Check protocol\tF5','TODO',
@@ -179,7 +182,49 @@ class MainWindow(wx.Frame):
dialog.Destroy()
return userProvidedFilename
# Event handlers:
# Are we dropping a changed file?
def ConfirmLoss(self,text=None):
"""
Try to drop the current file. If it was changed, try to save
(as)
Returns true after the user seems to be happy either way, false
if we need to cancel this.
"""
if self.editor.GetChanged():
# File changed, we need to confirm this
title = "Unsaved changes"
if text:
title = "%s - " + title
txt = "The protocol file '%s' has been modified.\n\n" % (self.filename)
txt = txt + "Do you want to"
txt = txt + " save your changes (Yes)"
txt = txt + " or"
txt = txt + " discard them (No)"
txt = txt + "?"
dialog = wx.MessageDialog(self,txt,title,wx.YES_NO | wx.CANCEL | wx.ICON_EXCLAMATION)
result = dialog.ShowModal()
dialog.Destroy()
if result == wx.ID_NO:
# Drop changes
return True
elif result == wx.ID_YES:
# First save(as)!
if self.OnSaveAs(None):
# Succeeded, we can continue with the operation
return True
else:
# Save did not succeed
return False
else:
# Assume cancel (wx.ID_CANCEL) otherwise
return False
else:
# File was not changed, so we can just proceed
return True
# Event handlers
def OnAbout(self, event):
dlg = About.AboutScyther(self)
@@ -187,25 +232,36 @@ class MainWindow(wx.Frame):
dlg.Destroy()
def OnExit(self, event):
self.Close() # Close the main window.
if self.ConfirmLoss("Exit"):
self.Close() # Close the main window.
return True
return False
def OnSave(self, event):
textfile = open(os.path.join(self.dirname, self.filename), 'w')
textfile.write(self.editor.GetText())
textfile.close()
self.editor.SetSaved()
return True
def OnOpen(self, event):
if self.askUserForFilename(style=wx.OPEN,
**self.defaultFileDialogOptions()):
textfile = open(os.path.join(self.dirname, self.filename), 'r')
self.editor.SetText(textfile.read())
textfile.close()
if self.ConfirmLoss("Open"):
if self.askUserForFilename(style=wx.OPEN,
**self.defaultFileDialogOptions()):
textfile = open(os.path.join(self.dirname, self.filename), 'r')
self.editor.SetText(textfile.read())
textfile.close()
self.editor.SetOpened()
return True
return False
def OnSaveAs(self, event):
if self.askUserForFilename(defaultFile=self.filename, style=wx.SAVE,
**self.defaultFileDialogOptions()):
self.OnSave(event)
os.chdir(self.dirname)
return True
return False
def RunScyther(self, mode):
# Clear errors before verification
@@ -220,8 +276,8 @@ class MainWindow(wx.Frame):
def OnAutoVerify(self, event):
self.RunScyther("autoverify")
def OnStatespace(self, event):
self.RunScyther("statespace")
def OnCharacterize(self, event):
self.RunScyther("characterize")
def OnCheck(self, event):
self.RunScyther("check")

View File

@@ -34,11 +34,12 @@ class ScytherThread(threading.Thread):
"""
# Override Thread's __init__ method to accept the parameters needed:
def __init__ ( self, spdl, options="", callback=None ):
def __init__ ( self, spdl, options="", callback=None, mode=None ):
self.spdl = spdl
self.options = options
self.callback = callback
self.mode = mode
threading.Thread.__init__ ( self )
def run(self):
@@ -49,6 +50,17 @@ class ScytherThread(threading.Thread):
if self.callback:
wx.CallAfter(self.callback, scyther, claims, summary)
def claimFixViewOne(self,claims):
if claims:
for cl in claims:
if len(cl.attacks) > 1:
# Fix it such that by default, only the best attack is
# shown, unless we are in characterize or check mode
# TODO [X] [CC] make switch-dependant.
if not self.mode in ["characterize","check"]:
cl.attacks = [cl.attacks[-1]]
return claims
def claimResults(self):
""" Convert spdl to result (using Scyther)
@@ -68,6 +80,8 @@ class ScytherThread(threading.Thread):
summary = str(scyther)
claims = self.claimFixViewOne(claims)
return (scyther, claims, summary)
#---------------------------------------------------------------------------
@@ -123,6 +137,7 @@ class AttackThread(threading.Thread):
def graphLine(txt):
fp.write("\t%s;\n" % (txt))
print txt # DEBUG ONLY
def setAttr(atxt,EdgeNodeDefAll=ALL):
if EdgeNodeDefAll == ALL:
@@ -139,6 +154,13 @@ class AttackThread(threading.Thread):
return
graphLine("%s [%s]" % (edge,atxt))
# Precompute font name
# Set a font with sans
# We only retrieve the name, so the size '9' here is
# irrelevant.
font = wx.Font(9,wx.SWISS,wx.NORMAL,wx.NORMAL)
self.fontname = font.GetFaceName()
# write all graph lines but add layout modifiers
for l in txt.splitlines():
fp.write(l)
@@ -151,23 +173,22 @@ class AttackThread(threading.Thread):
#graphLine("nodesep=0.1")
#graphLine("ranksep=0.001")
#graphLine("mindist=0.1")
if sys.platform.startswith("lin"):
# For Linux, choose Helvetica
# TODO
# This is really a Mac font so it might not be
# available. Still, it works better on my Ubuntu
# than Verdana, and finding a good sans default for
# linux seems problematic.
setAttr("fontname=\"Helvetica\"")
if sys.platform.startswith("mac"):
# For Mac choose Helvetica
setAttr("fontname=\"Helvetica\"")
if sys.platform.startswith("win"):
# For Windows choose Verdana
setAttr("fontname=\"Verdana\"")
# Set fontname
fontstring = "fontname=%s" % (self.fontname)
setAttr(fontstring,EDGE)
# Stupid Mac <> Graphviz bug fix
if (sys.platform.startswith("mac")) or (sys.platform.startswith("darwin")):
# Note that dot on Mac cannot find the fonts by default,
# and we have to set them accordingly.
os.environ["DOTFONTPATH"]="~/Library/Fonts:/Library/Fonts:/System/Library/Fonts"
# Select font size
if self.parent and self.parent.mainwin:
fontsize = self.parent.mainwin.settings.fontsize
setAttr("fontsize=%s" % fontsize)
#setAttr("height=\"0.1\"",NODE)
#setAttr("width=\"1.0\"",NODE)
#setAttr("margin=\"0.3,0.03\"",NODE)
@@ -188,25 +209,29 @@ class AttackThread(threading.Thread):
(fd2,fpname2) = Tempfile.tempcleaned(ext)
f = os.fdopen(fd2,'w')
cmd = "dot -T%s" % (type)
cmd = "dot -T%s >%s" % (type,fpname2)
# execute command
cin,cout = os.popen2(cmd,'b')
self.writeGraph(attack.scytherDot,cin)
cin.flush()
cin.close()
for l in cout.read():
f.write(l)
cout.close()
f.flush()
f.close()
# Print
print fpname2
raw_input()
# if this is done, store and report
attack.filetype = type
attack.file = fpname2 # this is where the file name is stored
# Maybe we should remove the temporary file... TODO
#---------------------------------------------------------------------------
class VerificationWindow(wx.Dialog):
@@ -344,7 +369,7 @@ class ResultWindow(wx.Frame):
views += self.BuildClaim(grid,claims[index],index+1)
if views > 0:
titlebar(7,"Classes",1)
titlebar(7,"Patterns",1)
self.SetSizer(grid)
self.Fit()
@@ -480,7 +505,7 @@ class ScytherRun(object):
# start the thread
self.verifywin.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
t = ScytherThread(self.spdl, self.options, self.verificationDone)
t = ScytherThread(self.spdl, self.options, self.verificationDone, self.mode)
t.start()
# after verification, we proceed to the callback below...

View File

@@ -150,13 +150,13 @@ class SettingsWindow(wx.Panel):
tstr += "--check "
elif mode == "autoverify":
tstr += "--auto-claims "
elif mode == "statespace":
elif mode == "characterize":
tstr += "--state-space "
# Anything else?
if self.misc != "":
tstr += " " + self.misc + " "
return tstr
return str(tstr) # turn it into a str (might have been unicode weirdness)
#---------------------------------------------------------------------------