Skip to content

Commit

Permalink
Good start on json.html, the sample JSON client
Browse files Browse the repository at this point in the history
  • Loading branch information
billstclair committed Mar 29, 2012
1 parent eb8dc39 commit 69e463d
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 27 deletions.
42 changes: 19 additions & 23 deletions src/client-json.lisp
Expand Up @@ -135,14 +135,18 @@
(defun assoc-json-value (key alist)
(cdr (assoc key alist :test #'string-equal)))

(defun blank-to-nil (x)
(if (blankp x) nil x))

(defmacro with-json-args (lambda-list args-alist &body body)
(let ((args-var (gensym "ARGS")))
`(let ((,args-var ,args-alist))
(let ,(loop for var-spec in lambda-list
for var = (if (listp var-spec) (first var-spec) var-spec)
for default = (and (listp var-spec) (second var-spec))
for val-form = `(assoc-json-value
,(string-downcase (string var)) ,args-var)
for val-form = `(blank-to-nil
(assoc-json-value
,(string-downcase (string var)) ,args-var))
collect `(,var ,(if default
`(or ,val-form ,default)
val-form)))
Expand Down Expand Up @@ -181,39 +185,29 @@
(destroy-password passphrase)))))

(defun json-newuser-internal (client passphrase args)
(with-json-args (keysize name privkey fetch-privkey? url coupon proxy)
(with-json-args (keysize name privkey url coupon proxy)
args
(ensure-string passphrase "passphrase")
(when (stringp keysize) (setf keysize (parse-integer keysize)))
(ensure-integer keysize "keysize" t)
(ensure-string name "name" t)
(ensure-string privkey "privkey" t)
(ensure-string url "url" t)
(ensure-string coupon "coupon" t)
(ensure-string proxy "proxy" t)
(when (cond (keysize (or privkey fetch-privkey?))
(privkey fetch-privkey?)
((not fetch-privkey?)
(when (cond (keysize privkey)
((not privkey)
(json-error
"One of keysize, privkey, and fetch-privkey? must be included")))
"One of keysize or privkey must be included")))
(json-error
"Only one of keysize, privkey, and fetch-privkey? may be included"))
"Only one of keysize and privkey may be included"))
(when (and url coupon)
(error "Only one of url and coupon may be included"))
(when (passphrase-exists-p client passphrase)
(json-error "There is already a client account for passphrase"))
(when proxy
(setf proxy (parse-proxy proxy)))
(when fetch-privkey?
(unless url
(json-error "url required to fetch private key from server"))
(verify-server client url nil proxy)
(when fetch-privkey?
(handler-case
(setf privkey (fetch-privkey client url passphrase
:http-proxy proxy))
(error (c)
(json-error "Error fetching private key from ~a: ~a"
url c)))))
(when (passphrase-exists-p client passphrase)
(json-error "There is already a client account for passphrase"))

(cond ((and privkey url)
;; Make sure we've got an account.
(verify-private-key client privkey passphrase url proxy))
Expand All @@ -235,17 +229,19 @@
(error (c)
(logout client)
(json-error "Failed to add server: ~a" c)))
(when fetch-privkey?
(setf (privkey-cached-p client) t))
session)))

(defun json-getprivkey (client args)
(with-json-args (passphrase) args
(when (blankp passphrase)
(json-error "Passphrase required for getprivkey"))
(login client passphrase)
(encode-rsa-private-key (privkey client) passphrase)))

(defun json-login (client args)
(with-json-args (passphrase) args
(when (blankp passphrase)
(json-error "Passphrase required for login"))
(let ((session (login-new-session client passphrase)))
(%setserver-json client)
session)))
Expand Down
4 changes: 3 additions & 1 deletion todo.txt
@@ -1,4 +1,6 @@
Webapp access to client.
Example JSON web client.

--quiet command line arg to prevent opening web serve

----------------------------------------------------------------------

Expand Down
4 changes: 4 additions & 0 deletions www/css/jquery-1.7.2.min.js

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions www/doc/json.txt
Expand Up @@ -14,7 +14,7 @@ Results vary by function and are documented with each function.
Error results are always returned as {"@type":"error","message":<string>}

["newuser",{"passphrase":<string>,"keysize":<integer>,"name":<string>,
"privkey":<string>,"fetch-privkey?":<boolean>,"url":<string>,
"privkey":<string>:<boolean>,"url":<string>,
"coupon":<string>,"proxy":<string>] => <session-string>
Create a new user with the given "passphrase". Error if already there.
All other parameters are optional
Expand All @@ -26,8 +26,6 @@ Error results are always returned as {"@type":"error","message":<string>}
That will create a local account on a client with no running server.
If you include a "url", will look for the account on that server.
If you include a "coupon", will register with that coupon on its server.
If "fetch-privkey?" is true, then "url" must be included, and
the cached private key is fetched from "url".
If "coupon" is included, it should be a coupon for
a truledger server on which you want to create an account.
This is not required if logging into a client with no running server,
Expand Down
167 changes: 167 additions & 0 deletions www/json.html
@@ -0,0 +1,167 @@
<html>
<head>
<link rel='stylesheet' type='text/css' href='css/docstyle.css'>
<link rel='stylesheet' type='text/css' href='css/tables.css'>
<title>Truledger JSON Client Sandbox</title>
<style>th { text-align: right; }</style>
<script src='css/jquery-1.7.2.min.js'></script>
<script>
function send(obj, processor) {
obj = JSON.stringify(obj);
$('#sent').html(obj);
$.post('json/', {'eval':obj}, function(data) {
$('#rcvd').html(JSON.stringify(data));
if (data && typeof(data)=='object' && data['@type']=='error') {
$('#error').html(data['message']);
} else {
$('#error').html('&nbsp');
processor(data);
}
}, 'JSON');
}

function ignore(data) {
}

function hide(cls, obj) {
if ($(obj).html().trim() == 'Hide') {
$('.'+cls).hide();
$(obj).html('Show');
} else {
$('.'+cls).show();
$(obj).html('Hide');
}
}

var session;
function returnSession(data) {
if (typeof(data) == 'string') {
session = data;
$('#session').html(session);
}
}
function login() {
passphrase = $('#passphrase').val();
send(['login',{'passphrase':passphrase}], returnSession);
}

function logout() {
if (session) {
send(['logout',{'session':session}],ignore);
session = false;
$('#session').html('None');
} else {
$('#sent').html('');
$('#rcvd').html('');
$('#error').html('Not logged in');
}
}

function returnPrivkey(data) {
if (typeof(data) == 'string') {
$('#privkey').html(data);
}
}

function getprivkey() {
passphrase = $('#passphrase').val();
send(['getprivkey',{'passphrase':passphrase}],
returnPrivkey);
}

function newuser() {
passphrase = $('#passphrase').val();
keysize = $('#keysize').val();
name = $('#name').val();
url = $('#url').val();
coupon = $('#coupon').val();
proxy = $('#proxy').val();
privkey = $('#privkey').val();
if (privkey != '') keysize = null;
send(['newuser',{'passphrase':passphrase,
'keysize':keysize,
'name':name,
'url':url,
'coupon':coupon,
'proxy':proxy,
'privkey':privkey,}],
returnSession);
}

</script>
</head>
<body onload='$("#passphrase").focus()'>
<h2>JSON Sandbox</h2>
<p>This page is for playing with the JSON interface to the Truledger client.</p>
<p>
<textarea id='sent' name='sent' cols='80' rows='5'>JSON sent to the server goes here.</textarea>
<br>
<textarea id='rcvd' name='rcvd' cols='80' rows='10'>JSON returned by the server goes here.</textarea>
</p>
<table>
<tr>
<th>&nbsp;</th>
<td><span id='error' style='color: red;'>&nbsp;</span></td>
</tr>
<tr>
<th>Session:</th>
<td id='session'>None</td>
</tr>
<tr>
<th>Passphrase:</th>
<td>
<input id='passphrase' name='passphrase' type='password' size='40'/>
<input type='submit' name='login' value='Login' onClick='login();'/>
<input type='submit' name='logout' value='Logout' onClick='logout();'/>
<input type='submit' name='getprivkey' value="Get Privkey"
onClick='getprivkey()'/>
</td>
</tr>
<tr>
<th>&nbsp;</th>
<td>
<a href='javascript:void(0)' onClick="javascript:hide('newuser',this)">
Hide</a> New User fields
</td>
</tr>
<tr class='newuser'>
<th>Key Size:</th>
<td>
<select id='keysize' name='keysize'>
<option value='512'>512</option>
<option value='1024'>1024</option>
<option value='2048'>2048</option>
<option value='3072'>3072</option>
<option value='4096'>4096</option>
</select>
</td>
</tr>
<tr class='newuser'>
<th>Name:</th>
<td><input id='name' name='name' type='text' size='30'/></td>
</tr>
<tr class='newuser'>
<th>URL:</th>
<td><input id='url' name='url' type='text' size='40'/></td>
</tr>
<tr class='newuser'>
<th>Coupon:</th>
<td><input id='coupon' name='coupon' type='text' size='40'/></td>
</tr>
<tr class='newuser'>
<th>Proxy:</th>
<td><input id='proxy' name='proxy' type='text' size='40'/></td>
</tr>
<tr class='newuser'>
<th>Privkey:</th>
<td><textarea id='privkey' cols='65' rows='10'></textarea></td>
</tr>
<tr class='newuser'>
<td>&nbsp;</td>
<td>
<input type='submit' name='newuser' value='New User' onClick='newuser()'/>
</td>
</tr>
</table>
</body>
</html>

0 comments on commit 69e463d

Please sign in to comment.