From 04bc1c81da02d39233087eff70e3afbe8a06f5aa Mon Sep 17 00:00:00 2001
From: Andreas Savvides
Date: Sun, 15 Sep 2013 18:41:46 +0100
Subject: [PATCH 01/40] Replacing tabs with whitespace for codebase consistency
---
coder-base/apps/wifi/app.js | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/coder-base/apps/wifi/app.js b/coder-base/apps/wifi/app.js
index 80c871f6..30f4faf6 100644
--- a/coder-base/apps/wifi/app.js
+++ b/coder-base/apps/wifi/app.js
@@ -90,26 +90,26 @@ exports.api_wifi_configure_handler = function( req, res ) {
var wpatemplate = "network={\n" +
- "\tssid=\"[ssid]\"\n" +
- "\tpsk=\"[password]\"\n" +
- "\tscan_ssid=1\n" +
- "\tpriority=10\n" +
- "}\n";
+ "\tssid=\"[ssid]\"\n" +
+ "\tpsk=\"[password]\"\n" +
+ "\tscan_ssid=1\n" +
+ "\tpriority=10\n" +
+ "}\n";
var weptemplate = "network={\n" +
- "\tssid=\"[ssid]\"\n" +
- "\twep_key0=\"[password]\"\n" +
- "\tscan_ssid=1\n" +
- "\tkey_mgmt=NONE\n" +
- "\tpriority=10\n" +
- "}\n";
+ "\tssid=\"[ssid]\"\n" +
+ "\twep_key0=\"[password]\"\n" +
+ "\tscan_ssid=1\n" +
+ "\tkey_mgmt=NONE\n" +
+ "\tpriority=10\n" +
+ "}\n";
var opentemplate = "network={\n" +
- "\tssid=\"[ssid]\"\n" +
- "\tscan_ssid=1\n" +
- "\tkey_mgmt=NONE\n" +
- "\tpriority=10\n" +
- "}\n";
+ "\tssid=\"[ssid]\"\n" +
+ "\tscan_ssid=1\n" +
+ "\tkey_mgmt=NONE\n" +
+ "\tpriority=10\n" +
+ "}\n";
var confentry="";
@@ -198,7 +198,7 @@ exports.api_wifi_list_handler = function( req, res ) {
var access_points = {};
var debug="";
- var addHighestSignal = function( ssid, type, signal ) {
+ var addHighestSignal = function( ssid, type, signal ) {
if ( !access_points[ssid] ) {
access_points[ssid] = { ssid: ssid, type: type, signal: signal };
} else if ( access_points[ssid].signal < signal ) {
From 730e1e659365cd3dddd1a85115f3da6a9be2af37 Mon Sep 17 00:00:00 2001
From: Andreas Savvides
Date: Sun, 15 Sep 2013 18:43:30 +0100
Subject: [PATCH 02/40] Using proper Python commenting
---
findcoder-appengine/api/coder.py | 36 +++++++++++++++-----------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/findcoder-appengine/api/coder.py b/findcoder-appengine/api/coder.py
index c37bba4c..3c752499 100644
--- a/findcoder-appengine/api/coder.py
+++ b/findcoder-appengine/api/coder.py
@@ -1,22 +1,20 @@
-/**
- * Coder for Raspberry Pi
- * A simple platform for experimenting with web stuff.
- * http://goo.gl/coder
- *
- * Copyright 2013 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+# Coder for Raspberry Pi
+# A simple platform for experimenting with web stuff.
+# http://goo.gl/coder
+
+# Copyright 2013 Google Inc. All Rights Reserved.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
import webapp2
import os
From 81ade68def27e2f72edbc120cf2703ba463327b7 Mon Sep 17 00:00:00 2001
From: Andreas Savvides
Date: Sun, 15 Sep 2013 18:44:10 +0100
Subject: [PATCH 03/40] Removing unused imports
---
findcoder-appengine/api/coder.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/findcoder-appengine/api/coder.py b/findcoder-appengine/api/coder.py
index 3c752499..c3dec7ef 100644
--- a/findcoder-appengine/api/coder.py
+++ b/findcoder-appengine/api/coder.py
@@ -17,12 +17,9 @@
# limitations under the License.
import webapp2
-import os
import time
-import logging
import re
import json
-import math
from google.appengine.api import memcache
CACHETIME = 120
From 44afb433582d521267643ecc24392956205ced84 Mon Sep 17 00:00:00 2001
From: Chris Matta
Date: Sun, 15 Sep 2013 15:23:07 -0400
Subject: [PATCH 04/40] missing close
in hello_coder index
---
coder-base/views/apps/hello_coder/index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/coder-base/views/apps/hello_coder/index.html b/coder-base/views/apps/hello_coder/index.html
index 26984c73..573af7d5 100644
--- a/coder-base/views/apps/hello_coder/index.html
+++ b/coder-base/views/apps/hello_coder/index.html
@@ -27,7 +27,7 @@
Hello Coder
-
Get started with Coder by exploring this app.
+
Get started with Coder by exploring this app.
Click the edit button "</>" to dive in.
It's at the top right.
From 209ca86a44c7f73ac86baf6a97a09bd4fb30db07 Mon Sep 17 00:00:00 2001
From: Ricky Pike
Date: Thu, 3 Oct 2013 18:07:22 -0500
Subject: [PATCH 05/40] Use vars instead of multiple ssh cert file strings
---
coder-base/server.js | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/coder-base/server.js b/coder-base/server.js
index f7ec4f97..160663f7 100644
--- a/coder-base/server.js
+++ b/coder-base/server.js
@@ -32,6 +32,7 @@ var util = require('util');
var cons = require('consolidate');
var params = require('express-params');
var querystring = require('querystring');
+var path = require('path');
var loadApp = function( loadpath ) {
@@ -136,11 +137,13 @@ var startSSLRedirect = function() {
var startSSL = function() {
+ privateKeyFile=path.normalize('certs/server.key');
+ certificateFile=path.normalize('certs/server.cert');
var privateKey="";
var certificate="";
try {
- privateKey = fs.readFileSync('certs/server.key').toString();
- certificate = fs.readFileSync('certs/server.cert').toString();
+ privateKey = fs.readFileSync(privateKeyFile).toString();
+ certificate = fs.readFileSync(certificateFile).toString();
} catch ( e ) {
util.print( "no certificate found. generating self signed cert.\n" );
}
@@ -150,30 +153,30 @@ var startSSL = function() {
} else {
var spawn = require('child_process').spawn;
- var genSelfSignedCert = function() {
+ var genSelfSignedCert = function(keyFile, certFile) {
var genkey = spawn( 'openssl', [
'req', '-x509', '-nodes',
'-days', '365',
'-newkey', 'rsa:2048',
- '-keyout', 'certs/server.key',
- '-out', 'certs/server.cert',
+ '-keyout', keyFile,
+ '-out', certFile,
'-subj',
'/C=' + config.country + '/ST=' + config.state + "/L=" + config.locale + "/CN=" + config.commonName + "/subjectAltName=" + config.subjectAltName
]);
genkey.stdout.on('data', function(d) { util.print(d) } );
genkey.stderr.on('data', function(d) { util.print(d) } );
genkey.addListener( 'exit', function( code, signal ) {
- fs.chmodSync('certs/server.key', '600');
+ fs.chmodSync(privateKeyFile, '600');
loadServer();
});
};
var loadServer = function() {
- privateKey = fs.readFileSync('certs/server.key').toString();
- certificate = fs.readFileSync('certs/server.cert').toString();
+ privateKey = fs.readFileSync(privateKeyFile).toString();
+ certificate = fs.readFileSync(certificateFile).toString();
https.createServer({ key: privateKey, cert: certificate }, sslapp).listen( config.listenPort, config.listenIP );
};
- genSelfSignedCert();
+ genSelfSignedCert(privateKeyFile, certificateFile);
}
};
From 00a9c7fc5fa68b96761bc6f1b778efecc141848e Mon Sep 17 00:00:00 2001
From: Jason Striegel
Date: Tue, 22 Oct 2013 19:28:10 -0700
Subject: [PATCH 06/40] Restructure: separate pi-specific apps and added
localhost server.
All apps have moved to /coder-apps/platform/[appname] and some crude
scripts have been added to make moving files between coder-base
and the coder-apps structure a bit easier.
---
INSTALL | 61 ++
coder-apps/archive_app.sh | 35 +
coder-apps/common/auth/app/app.js | 628 ++++++++++++++++++
.../common/auth/app}/meta.json | 0
.../common/auth/static}/css/index.css | 0
.../common/auth/static}/js/index.js | 0
.../common/auth/static/media/.gitignore | 0
coder-apps/common/auth/views/index.html | 108 +++
.../common/boilerplate/app}/app.js | 0
.../common/boilerplate/app}/meta.json | 0
.../common/boilerplate/static}/css/index.css | 0
.../common/boilerplate/static}/js/index.js | 0
.../boilerplate/static/media/.gitignore | 0
.../common/boilerplate/views}/index.html | 0
.../common/coder/app}/app.js | 0
.../common/coder/app}/meta.json | 0
.../common/coder/static}/css/index.css | 0
coder-apps/common/coder/static/js/index.js | 454 +++++++++++++
.../common/coder/static/media/.gitignore | 0
.../common/coder/static}/media/myapps_tip.png | Bin
.../common/coder/static}/media/newapp_tip.png | Bin
.../coder/static}/media/settings_tip.png | Bin
coder-apps/common/coder/views/index.html | 138 ++++
.../common/coderlib/app}/app.js | 0
.../common/coderlib/app}/meta.json | 0
.../common/coderlib/static}/css/index.css | 0
.../common/coderlib/static}/js/index.js | 0
.../common/coderlib/static/media/.gitignore | 0
coder-apps/common/coderlib/views/index.html | 0
.../common/editor/app}/app.js | 2 +-
.../common/editor/app}/meta.json | 2 +-
.../common/editor/static}/css/index.css | 0
.../common/editor/static}/js/index.js | 0
.../common/editor/static/media/.gitignore | 0
.../common/editor/views}/index.html | 0
.../common/eyeball/app}/app.js | 0
.../common/eyeball/app}/meta.json | 2 +-
.../common/eyeball/static}/css/index.css | 2 +-
.../common/eyeball/static}/js/index.js | 0
.../common/eyeball/static/media/.gitignore | 0
.../common/eyeball/views}/index.html | 0
.../common/game2d/app}/app.js | 0
.../common/game2d/app}/meta.json | 0
.../common/game2d/static}/css/index.css | 0
.../common/game2d/static}/js/index.js | 0
.../common/game2d/static/media/.gitignore | 0
.../common/game2d/views}/index.html | 0
.../common/hello_coder/app}/app.js | 0
.../common/hello_coder/app}/meta.json | 0
.../common/hello_coder/static}/css/index.css | 0
.../common/hello_coder/static}/js/index.js | 0
.../hello_coder/static/media/.gitignore | 0
.../common/hello_coder/views}/index.html | 0
.../common/space_rocks_/app}/app.js | 0
.../common/space_rocks_/app}/meta.json | 0
.../common/space_rocks_/static}/css/index.css | 0
.../common/space_rocks_/static}/js/index.js | 0
.../space_rocks_/static/media/.gitignore | 0
.../space_rocks_/static}/media/die_ship.mp3 | Bin
.../space_rocks_/static}/media/die_ship.ogg | Bin
.../space_rocks_/static}/media/die_ship.wav | Bin
.../static}/media/die_spacerock.mp3 | Bin
.../static}/media/die_spacerock.ogg | Bin
.../static}/media/die_spacerock.wav | Bin
.../static}/media/spacerocks_shoot.mp3 | Bin
.../static}/media/spacerocks_shoot.ogg | Bin
.../static}/media/spacerocks_shoot.wav | Bin
.../space_rocks_/static}/media/thrust.mp3 | Bin
.../space_rocks_/static}/media/thrust.ogg | Bin
.../space_rocks_/static}/media/thrust.wav | Bin
.../common/space_rocks_/views}/index.html | 0
coder-apps/install_app.sh | 34 +
coder-apps/install_common.sh | 29 +
coder-apps/install_pi.sh | 25 +
.../auth => coder-apps/pi/auth/app}/app.js | 0
coder-apps/pi/auth/app/meta.json | 8 +
coder-apps/pi/auth/static/css/index.css | 133 ++++
coder-apps/pi/auth/static/js/index.js | 474 +++++++++++++
coder-apps/pi/auth/static/media/.gitignore | 0
.../pi/auth/views}/index.html | 0
coder-apps/pi/coder/app/app.js | 495 ++++++++++++++
coder-apps/pi/coder/app/meta.json | 8 +
coder-apps/pi/coder/static/css/index.css | 489 ++++++++++++++
.../pi/coder/static}/js/index.js | 0
coder-apps/pi/coder/static/media/.gitignore | 0
.../pi/coder/static/media/myapps_tip.png | Bin 0 -> 9585 bytes
.../pi/coder/static/media/newapp_tip.png | Bin 0 -> 10125 bytes
.../pi/coder/static/media/settings_tip.png | Bin 0 -> 7218 bytes
.../pi/coder/views}/index.html | 0
.../wifi => coder-apps/pi/wifi/app}/app.js | 0
.../wifi => coder-apps/pi/wifi/app}/meta.json | 0
.../pi/wifi/static}/css/index.css | 0
.../pi/wifi/static}/js/index.js | 0
.../pi/wifi/views}/index.html | 0
coder-base/apps/.gitignore | 0
coder-base/config.js.default | 28 +
coder-base/config.js.localhost | 28 +
coder-base/localserver.js | 177 +++++
coder-base/package.json | 3 +-
coder-base/server.js | 8 +-
coder-base/static/apps/.gitignore | 0
.../coder-base}/sudo_scripts/reboot | 0
.../coder-base}/sudo_scripts/setpipass | 0
.../coder-base}/sudo_scripts/wpa_cli_apscan | 0
.../coder-base}/sudo_scripts/wpa_cli_scan | 0
.../sudo_scripts/wpa_cli_scanresults | 0
106 files changed, 3364 insertions(+), 7 deletions(-)
create mode 100644 INSTALL
create mode 100755 coder-apps/archive_app.sh
create mode 100644 coder-apps/common/auth/app/app.js
rename {coder-base/apps/auth => coder-apps/common/auth/app}/meta.json (100%)
rename {coder-base/static/apps/auth => coder-apps/common/auth/static}/css/index.css (100%)
rename {coder-base/static/apps/auth => coder-apps/common/auth/static}/js/index.js (100%)
rename coder-base/views/apps/coderlib/index.html => coder-apps/common/auth/static/media/.gitignore (100%)
create mode 100644 coder-apps/common/auth/views/index.html
rename {coder-base/apps/boilerplate => coder-apps/common/boilerplate/app}/app.js (100%)
rename {coder-base/apps/boilerplate => coder-apps/common/boilerplate/app}/meta.json (100%)
rename {coder-base/static/apps/boilerplate => coder-apps/common/boilerplate/static}/css/index.css (100%)
rename {coder-base/static/apps/boilerplate => coder-apps/common/boilerplate/static}/js/index.js (100%)
create mode 100644 coder-apps/common/boilerplate/static/media/.gitignore
rename {coder-base/views/apps/boilerplate => coder-apps/common/boilerplate/views}/index.html (100%)
rename {coder-base/apps/coder => coder-apps/common/coder/app}/app.js (100%)
rename {coder-base/apps/coder => coder-apps/common/coder/app}/meta.json (100%)
rename {coder-base/static/apps/coder => coder-apps/common/coder/static}/css/index.css (100%)
create mode 100644 coder-apps/common/coder/static/js/index.js
create mode 100644 coder-apps/common/coder/static/media/.gitignore
rename {coder-base/static/apps/coder => coder-apps/common/coder/static}/media/myapps_tip.png (100%)
rename {coder-base/static/apps/coder => coder-apps/common/coder/static}/media/newapp_tip.png (100%)
rename {coder-base/static/apps/coder => coder-apps/common/coder/static}/media/settings_tip.png (100%)
create mode 100644 coder-apps/common/coder/views/index.html
rename {coder-base/apps/coderlib => coder-apps/common/coderlib/app}/app.js (100%)
rename {coder-base/apps/coderlib => coder-apps/common/coderlib/app}/meta.json (100%)
rename {coder-base/static/apps/coderlib => coder-apps/common/coderlib/static}/css/index.css (100%)
rename {coder-base/static/apps/coderlib => coder-apps/common/coderlib/static}/js/index.js (100%)
create mode 100644 coder-apps/common/coderlib/static/media/.gitignore
create mode 100644 coder-apps/common/coderlib/views/index.html
rename {coder-base/apps/editor => coder-apps/common/editor/app}/app.js (99%)
rename {coder-base/apps/editor => coder-apps/common/editor/app}/meta.json (81%)
rename {coder-base/static/apps/editor => coder-apps/common/editor/static}/css/index.css (100%)
rename {coder-base/static/apps/editor => coder-apps/common/editor/static}/js/index.js (100%)
create mode 100644 coder-apps/common/editor/static/media/.gitignore
rename {coder-base/views/apps/editor => coder-apps/common/editor/views}/index.html (100%)
rename {coder-base/apps/eyeball => coder-apps/common/eyeball/app}/app.js (100%)
rename {coder-base/apps/eyeball => coder-apps/common/eyeball/app}/meta.json (81%)
rename {coder-base/static/apps/eyeball => coder-apps/common/eyeball/static}/css/index.css (97%)
rename {coder-base/static/apps/eyeball => coder-apps/common/eyeball/static}/js/index.js (100%)
create mode 100644 coder-apps/common/eyeball/static/media/.gitignore
rename {coder-base/views/apps/eyeball => coder-apps/common/eyeball/views}/index.html (100%)
rename {coder-base/apps/game2d => coder-apps/common/game2d/app}/app.js (100%)
rename {coder-base/apps/game2d => coder-apps/common/game2d/app}/meta.json (100%)
rename {coder-base/static/apps/game2d => coder-apps/common/game2d/static}/css/index.css (100%)
rename {coder-base/static/apps/game2d => coder-apps/common/game2d/static}/js/index.js (100%)
create mode 100644 coder-apps/common/game2d/static/media/.gitignore
rename {coder-base/views/apps/game2d => coder-apps/common/game2d/views}/index.html (100%)
rename {coder-base/apps/hello_coder => coder-apps/common/hello_coder/app}/app.js (100%)
rename {coder-base/apps/hello_coder => coder-apps/common/hello_coder/app}/meta.json (100%)
rename {coder-base/static/apps/hello_coder => coder-apps/common/hello_coder/static}/css/index.css (100%)
rename {coder-base/static/apps/hello_coder => coder-apps/common/hello_coder/static}/js/index.js (100%)
create mode 100644 coder-apps/common/hello_coder/static/media/.gitignore
rename {coder-base/views/apps/hello_coder => coder-apps/common/hello_coder/views}/index.html (100%)
rename {coder-base/apps/space_rocks_ => coder-apps/common/space_rocks_/app}/app.js (100%)
rename {coder-base/apps/space_rocks_ => coder-apps/common/space_rocks_/app}/meta.json (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/css/index.css (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/js/index.js (100%)
create mode 100644 coder-apps/common/space_rocks_/static/media/.gitignore
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/die_ship.mp3 (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/die_ship.ogg (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/die_ship.wav (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/die_spacerock.mp3 (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/die_spacerock.ogg (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/die_spacerock.wav (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/spacerocks_shoot.mp3 (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/spacerocks_shoot.ogg (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/spacerocks_shoot.wav (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/thrust.mp3 (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/thrust.ogg (100%)
rename {coder-base/static/apps/space_rocks_ => coder-apps/common/space_rocks_/static}/media/thrust.wav (100%)
rename {coder-base/views/apps/space_rocks_ => coder-apps/common/space_rocks_/views}/index.html (100%)
create mode 100755 coder-apps/install_app.sh
create mode 100755 coder-apps/install_common.sh
create mode 100755 coder-apps/install_pi.sh
rename {coder-base/apps/auth => coder-apps/pi/auth/app}/app.js (100%)
create mode 100644 coder-apps/pi/auth/app/meta.json
create mode 100644 coder-apps/pi/auth/static/css/index.css
create mode 100644 coder-apps/pi/auth/static/js/index.js
create mode 100644 coder-apps/pi/auth/static/media/.gitignore
rename {coder-base/views/apps/auth => coder-apps/pi/auth/views}/index.html (100%)
create mode 100644 coder-apps/pi/coder/app/app.js
create mode 100644 coder-apps/pi/coder/app/meta.json
create mode 100644 coder-apps/pi/coder/static/css/index.css
rename {coder-base/static/apps/coder => coder-apps/pi/coder/static}/js/index.js (100%)
create mode 100644 coder-apps/pi/coder/static/media/.gitignore
create mode 100644 coder-apps/pi/coder/static/media/myapps_tip.png
create mode 100644 coder-apps/pi/coder/static/media/newapp_tip.png
create mode 100644 coder-apps/pi/coder/static/media/settings_tip.png
rename {coder-base/views/apps/coder => coder-apps/pi/coder/views}/index.html (100%)
rename {coder-base/apps/wifi => coder-apps/pi/wifi/app}/app.js (100%)
rename {coder-base/apps/wifi => coder-apps/pi/wifi/app}/meta.json (100%)
rename {coder-base/static/apps/wifi => coder-apps/pi/wifi/static}/css/index.css (100%)
rename {coder-base/static/apps/wifi => coder-apps/pi/wifi/static}/js/index.js (100%)
rename {coder-base/views/apps/wifi => coder-apps/pi/wifi/views}/index.html (100%)
create mode 100644 coder-base/apps/.gitignore
create mode 100644 coder-base/config.js.default
create mode 100644 coder-base/config.js.localhost
create mode 100644 coder-base/localserver.js
create mode 100644 coder-base/static/apps/.gitignore
rename {coder-base => raspbian-addons/home/coder/coder-dist/coder-base}/sudo_scripts/reboot (100%)
rename {coder-base => raspbian-addons/home/coder/coder-dist/coder-base}/sudo_scripts/setpipass (100%)
rename {coder-base => raspbian-addons/home/coder/coder-dist/coder-base}/sudo_scripts/wpa_cli_apscan (100%)
rename {coder-base => raspbian-addons/home/coder/coder-dist/coder-base}/sudo_scripts/wpa_cli_scan (100%)
rename {coder-base => raspbian-addons/home/coder/coder-dist/coder-base}/sudo_scripts/wpa_cli_scanresults (100%)
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 00000000..67959a96
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,61 @@
+
+CODER FOR RASPBERRY PI
+The easy way...
+
+Coder for Raspberry Pi is distributed as a Pi SD Card image.
+If you want to go the easy route, please check out the
+documentation at http://goo.gl/coder
+
+
+
+EVERYONE ELSE
+
+If you want to install Coder on something else, or would
+like to install it on an existing Raspberry Pi, you can
+manually install it as well.
+
+BEFORE YOU START:
+ I recommend you do this as a normal user and not root.
+ The official pi distro has a "coder" user that Coder runs
+ under, and ports 80 and 433 are forwarded to 8080/8081.
+
+MANUAL INSTALL:
+
+1. You need to have node.js and npm installed
+
+2. Download Coder from git.
+ # git clone https://github.com/googlecreativelab/coder.git
+
+3. In coder-base run "npm install" to download all the
+ needed modules.
+
+4. Install the basic Coder apps.
+ # cd coder-apps
+ # ./install_common.sh
+
+5. Edit config.js to your liking. I recommend starting
+ with the settings in config.js.localhost and running
+ the localhost server.
+
+6. Start Coder
+ # cd coder-base
+ # node localserver.js
+
+
+If you want to run Coder on an external port, you'll need
+to run server.js instead of localserver.js. This requires
+a bit of port forwarding setup in iptables. Look in
+the raspbian-addons directory to see the customizations that
+were made to the stock raspbian distro.
+
+The raspberry pi version of Coder has some other
+tweaks that allow you to change your wifi settings
+and keep your Pi password in sync with your Coder password.
+There's some convoluted system configuration involved, which is
+probably why you'd want to start with the Coder disk image,
+but the modified apps are available by running ./install_pi.sh
+after step 4. Modifications to the stock raspbian configuration
+can be found in raspbian-addons.
+
+
+
diff --git a/coder-apps/archive_app.sh b/coder-apps/archive_app.sh
new file mode 100755
index 00000000..0012ca5a
--- /dev/null
+++ b/coder-apps/archive_app.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+##
+## Copies an application from the coder-base working directory to
+## the coder-apps directory.
+##
+## sh archive_app appname base_path apps_path
+##
+## Eg.
+## sh archive_app hello_coder ../coder-base/ ./common/
+
+if [ $# != 3 ]
+ then
+ echo -e "\nUse:\narchive_app appname base_path apps_path\n"
+ exit
+fi
+
+app=$1
+base=$2
+dest=$3
+
+mkdir "$dest/$app"
+mkdir "$dest/$app/app"
+mkdir "$dest/$app/static"
+mkdir "$dest/$app/static/js"
+mkdir "$dest/$app/static/css"
+mkdir "$dest/$app/static/media"
+mkdir "$dest/$app/views"
+touch "$dest/$app/static/media/.gitignore"
+
+cp $base/apps/$app/* $dest/$app/app/
+cp $base/views/apps/$app/* $dest/$app/views/
+cp $base/static/apps/$app/js/* $dest/$app/static/js/
+cp $base/static/apps/$app/css/* $dest/$app/static/css/
+cp $base/static/apps/$app/media/* $dest/$app/static/media/
diff --git a/coder-apps/common/auth/app/app.js b/coder-apps/common/auth/app/app.js
new file mode 100644
index 00000000..dacd9034
--- /dev/null
+++ b/coder-apps/common/auth/app/app.js
@@ -0,0 +1,628 @@
+/**
+ * Coder for Raspberry Pi
+ * A simple platform for experimenting with web stuff.
+ * http://goo.gl/coder
+ *
+ * Copyright 2013 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var mustache = require('mustache');
+var util = require('util');
+var fs = require('fs');
+var bcrypt = require('bcrypt');
+
+//stores cache of password hash and device name
+var device_settings = {
+ password_hash: '',
+ device_name: '',
+ hostname: '',
+ coder_owner: '',
+ coder_color: '#3e3e3e'
+};
+
+
+exports.settings={};
+//These are dynamically updated by the runtime
+//settings.appname - the app id (folder) where your app is installed
+//settings.viewpath - prefix to where your view html files are located
+//settings.staticurl - base url path to static assets /static/apps/appname
+//settings.appurl - base url path to this app /app/appname
+//settings.device_name - name the user gave to their coder "Susie's Coder"
+
+
+exports.get_routes = [
+ { path:'/', handler:'index_handler'},
+ { path:'/login', handler:'login_handler'},
+ { path:'/logout', handler:'logout_handler'},
+ { path:'/configure', handler:'configure_handler'},
+ { path:'/addpassword', handler:'addpassword_handler'},
+ { path:'/changepassword', handler:'changepassword_handler'},
+ { path: '/api/devicename/get', handler: 'api_devicename_get_handler' },
+ { path: '/api/codercolor/get', handler: 'api_codercolor_get_handler' },
+ { path: '/api/coderowner/get', handler: 'api_coderowner_get_handler' }
+];
+
+
+exports.post_routes = [
+ { path: '/api/login', handler: 'api_login_handler' },
+ { path: '/api/logout', handler: 'api_logout_handler' },
+ { path: '/api/devicename/set', handler: 'api_devicename_set_handler' },
+ { path: '/api/codercolor/set', handler: 'api_codercolor_set_handler' },
+ { path: '/api/coderowner/set', handler: 'api_coderowner_set_handler' },
+ { path: '/api/addpassword', handler: 'api_addpassword_handler' },
+ { path: '/api/changepassword', handler: 'api_changepassword_handler' }
+];
+
+exports.on_destroy = function() {
+};
+
+
+exports.isAuthenticated = function( req ) {
+ if ( typeof req.session !== 'undefined' && typeof req.session.authenticated !== 'undefined' ) {
+ return req.session.authenticated === true;
+ }
+ return false;
+};
+
+exports.isConfigured = function() {
+ if ( typeof device_settings.device_name !== 'undefined' && device_settings.device_name !== '' &&
+ typeof device_settings.hostname !== 'undefined' && device_settings.hostname !== '' ) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
+exports.hasPassword = function() {
+ if ( typeof device_settings.password_hash !== 'undefined' && device_settings.password_hash !== '' ) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
+exports.getDeviceName = function() {
+ return device_settings.device_name;
+};
+exports.getCoderOwner = function() {
+ return device_settings.coder_owner;
+};
+exports.getCoderColor = function() {
+ return device_settings.coder_color;
+};
+
+exports.authenticate = function( req, password ) {
+
+ var authenticated = bcrypt.compareSync( password, device_settings.password_hash );
+ if ( authenticated ) {
+ req.session.authenticated = true;
+ }
+
+ return authenticated;
+};
+
+exports.logout = function( req ) {
+
+ req.session.authenticated = false;
+};
+
+
+exports.index_handler = function( req, res ) {
+
+ var firstuse = "?firstuse";
+ if ( typeof( req.param('firstuse') ) === 'undefined' ) {
+ firstuse = "";
+ }
+
+ if ( !exports.isConfigured() ) {
+ res.redirect('/app/auth/configure?firstuse');
+ } else if ( !exports.hasPassword() ) {
+ res.redirect('/app/auth/addpassword?firstuse');
+ } else if ( !exports.isAuthenticated(req) ) {
+ res.redirect('/app/auth/login' + firstuse);
+ } else {
+ res.redirect('/app/coder' + firstuse);
+ }
+};
+
+exports.addpassword_handler = function( req, res ) {
+ var tmplvars = {};
+ tmplvars['static_url'] = exports.settings.staticurl;
+ tmplvars['app_name'] = exports.settings.appname;
+ tmplvars['app_url'] = exports.settings.appurl;
+ tmplvars['device_name'] = exports.settings.device_name;
+ tmplvars['page_mode'] = "addpassword";
+
+ //only allow this step if they have not yet set a password
+ if ( !exports.hasPassword() ) {
+ res.render( exports.settings.viewpath + '/index', tmplvars );
+ } else {
+ res.redirect('/app/auth/login');
+ }
+};
+
+exports.changepassword_handler = function( req, res ) {
+ var tmplvars = {};
+ tmplvars['static_url'] = exports.settings.staticurl;
+ tmplvars['app_name'] = exports.settings.appname;
+ tmplvars['app_url'] = exports.settings.appurl;
+ tmplvars['device_name'] = exports.settings.device_name;
+ tmplvars['page_mode'] = "changepassword";
+
+ //only allow this step if they are authenticated
+ if ( exports.isAuthenticated(req) ) {
+ res.render( exports.settings.viewpath + '/index', tmplvars );
+ } else {
+ res.redirect('/app/auth/login');
+ }
+};
+
+exports.configure_handler = function( req, res ) {
+ var tmplvars = {};
+ tmplvars['static_url'] = exports.settings.staticurl;
+ tmplvars['app_name'] = exports.settings.appname;
+ tmplvars['app_url'] = exports.settings.appurl;
+ tmplvars['device_name'] = exports.settings.device_name;
+ tmplvars['page_mode'] = "configure";
+
+ //only allow this step if they are authenticated or have not yet set a password
+ if ( exports.isAuthenticated(req) || !exports.hasPassword() ) {
+ res.render( exports.settings.viewpath + '/index', tmplvars );
+ } else {
+ res.redirect('/app/auth/login');
+ }
+};
+
+exports.api_devicename_get_handler = function( req, res ) {
+ res.json({
+ device_name: exports.getDeviceName()
+ });
+};
+exports.api_codercolor_get_handler = function( req, res ) {
+ res.json({
+ coder_color: exports.getCoderColor()
+ });
+};
+exports.api_coderowner_get_handler = function( req, res ) {
+ //only allow this step if they are authenticated or have not yet set a password
+ if ( !exports.isAuthenticated(req) && exports.hasPassword() ) {
+ res.json({
+ status: "error",
+ error: "not authenticated"
+ });
+ return;
+ }
+ res.json({
+ coder_owner: exports.getCoderOwner()
+ });
+};
+
+exports.api_devicename_set_handler = function( req, res ) {
+
+ //only allow this step if they are authenticated or have not yet set a password
+ if ( !exports.isAuthenticated(req) && exports.hasPassword() ) {
+ res.json({
+ status: "error",
+ error: "not authenticated"
+ });
+ return;
+ }
+
+ var devicename = req.param('device_name');
+ if ( !devicename || devicename === "" || !isValidDeviceName( devicename ) ) {
+ res.json({
+ status: 'error',
+ error: "invalid device name"
+ });
+ return;
+ }
+
+ device_settings.device_name = devicename;
+ device_settings.hostname = hostnameFromDeviceName( devicename );
+
+ err = saveDeviceSettings();
+
+ if ( !err ) {
+ res.json({
+ status: "success",
+ device_name: device_settings.device_name,
+ hostname: device_settings.hostname
+ });
+ } else {
+ res.json({
+ status: "error",
+ error: "could not save device settings"
+ });
+ }
+
+};
+
+
+exports.api_coderowner_set_handler = function( req, res ) {
+
+ //only allow this step if they are authenticated or have not yet set a password
+ if ( !exports.isAuthenticated(req) && exports.hasPassword() ) {
+ res.json({
+ status: "error",
+ error: "not authenticated"
+ });
+ return;
+ }
+
+ var owner = req.param('coder_owner');
+ if ( typeof owner === 'undefined' ) {
+ res.json({
+ status: 'error',
+ error: "invalid owner name"
+ });
+ return;
+ }
+
+ device_settings.coder_owner = owner;
+
+ err = saveDeviceSettings();
+
+ if ( !err ) {
+ res.json({
+ status: "success",
+ coder_owner: device_settings.coder_owner
+ });
+ } else {
+ res.json({
+ status: "error",
+ error: "could not save device settings"
+ });
+ }
+
+};
+
+exports.api_codercolor_set_handler = function( req, res ) {
+
+ //only allow this step if they are authenticated or have not yet set a password
+ if ( !exports.isAuthenticated(req) && exports.hasPassword() ) {
+ res.json({
+ status: "error",
+ error: "not authenticated"
+ });
+ return;
+ }
+
+ var color = req.param('coder_color');
+ if ( typeof color === 'undefined' || !isValidColor( color ) ) {
+ res.json({
+ status: 'error',
+ error: "invalid color"
+ });
+ return;
+ }
+
+ device_settings.coder_color = color;
+
+ err = saveDeviceSettings();
+
+ if ( !err ) {
+ res.json({
+ status: "success",
+ coder_color: device_settings.coder_color
+ });
+ } else {
+ res.json({
+ status: "error",
+ error: "could not save device settings"
+ });
+ }
+
+};
+
+exports.api_addpassword_handler = function( req, res ) {
+
+ //only allow this step if they have not yet set a password
+ if ( exports.hasPassword() ) {
+ res.json({
+ status: "error",
+ error: "not authenticated"
+ });
+ return;
+ }
+
+ var pass = req.param('password');
+ if ( !pass || pass === "" || !isValidPassword( pass ) ) {
+ res.json({
+ status: 'error',
+ error: getPasswordProblem( pass )
+ });
+ return;
+ }
+
+ var spawn = require('child_process').spawn;
+ var err=0;
+ //device_settings.device_name = devicename;
+ var erroutput = "";
+ var output = "";
+ //var setpipass = process.cwd() + '/sudo_scripts/setpipass';
+ //var setpass = spawn( '/usr/bin/sudo', [setpipass] );
+ //setpass.stdout.on( 'data', function( d ) {
+ // output += d;
+ //});
+ //setpass.stderr.on( 'data', function( d ) {
+ // erroutput += d;
+ //});
+
+ //setpass.addListener( 'exit', function( code, signal ) {
+ var completed = function( code, signal ) {
+ err = code;
+
+
+ if ( err ) {
+ res.json({
+ status: "error",
+ error: erroutput
+ });
+ return;
+ }
+
+ //TODO - Load hashed password
+ var s = bcrypt.genSaltSync(10);
+ var h = bcrypt.hashSync( pass, s );
+ util.log("PASSWORD INITIALIZED");
+ device_settings.password_hash = h;
+ err = saveDeviceSettings();
+
+ if ( !err ) {
+ res.json({
+ status: "success"
+ });
+ } else {
+ res.json({
+ status: "error",
+ error: "Could not save device settings."
+ });
+ }
+
+ };
+
+ completed();
+
+ //setpass.stdin.write(pass + '\n');
+ //setpass.stdin.write(pass + '\n');
+ //setpass.stdin.end();
+
+};
+
+
+
+exports.api_changepassword_handler = function( req, res ) {
+
+ //only allow this step if they are authenticated
+ if ( !exports.isAuthenticated(req) ) {
+ res.json({
+ status: "error",
+ error: "not authenticated"
+ });
+ return;
+ }
+
+ var oldpass = req.param('oldpassword');
+ var pass = req.param('password');
+
+ //Make sure old pass is set and matches
+ if ( typeof oldpass === 'undefined' || oldpass === ""
+ || !bcrypt.compareSync( oldpass, device_settings.password_hash ) ) {
+ res.json({
+ status: 'error',
+ error: "old password was incorrect"
+ });
+ return;
+ }
+
+ if ( !pass || pass === "" || !isValidPassword( pass ) ) {
+ res.json({
+ status: 'error',
+ error: getPasswordProblem( pass )
+ });
+ return;
+ }
+
+ var spawn = require('child_process').spawn;
+ var err=0;
+ //device_settings.device_name = devicename;
+ var erroutput = "";
+ var output = "";
+ var setpipass = process.cwd() + '/sudo_scripts/setpipass';
+ var setpass = spawn( '/usr/bin/sudo', [setpipass] );
+ setpass.stdout.on( 'data', function( d ) {
+ output += d;
+ });
+ setpass.stderr.on( 'data', function( d ) {
+ erroutput += d;
+ });
+
+ setpass.addListener( 'exit', function( code, signal ) {
+ err = code;
+
+
+ if ( err ) {
+ res.json({
+ status: "error",
+ error: erroutput
+ });
+ return;
+ }
+
+ //TODO - Load hashed password
+ var s = bcrypt.genSaltSync(10);
+ var h = bcrypt.hashSync( pass, s );
+ util.log("PASSWORD INITIALIZED");
+ device_settings.password_hash = h;
+ err = saveDeviceSettings();
+
+ if ( !err ) {
+ res.json({
+ status: "success"
+ });
+ } else {
+ res.json({
+ status: "error",
+ error: "Could not save device settings."
+ });
+ }
+
+ });
+ setpass.stdin.write(pass + '\n');
+ setpass.stdin.write(pass + '\n');
+ setpass.stdin.end();
+
+};
+
+
+exports.login_handler = function( req, res ) {
+ var tmplvars = {};
+ tmplvars['static_url'] = exports.settings.staticurl;
+ tmplvars['app_name'] = exports.settings.appname;
+ tmplvars['app_url'] = exports.settings.appurl;
+ tmplvars['device_name'] = exports.settings.device_name;
+ tmplvars['page_mode'] = "login";
+
+
+ //TODO - should this log you out automatically?
+ req.session.authenticated = false;
+ res.render( exports.settings.viewpath + '/index', tmplvars );
+};
+
+exports.logout_handler = function( req, res ) {
+ var tmplvars = {};
+ tmplvars['static_url'] = exports.settings.staticurl;
+ tmplvars['app_name'] = exports.settings.appname;
+ tmplvars['app_url'] = exports.settings.appurl;
+ tmplvars['device_name'] = exports.settings.device_name;
+ tmplvars['page_mode'] = "logout";
+
+ req.session.authenticated = false;
+ res.render( exports.settings.viewpath + '/index', tmplvars );
+};
+
+exports.api_login_handler = function( req, res ) {
+ if ( typeof req.body.password !== 'undefined' && req.body.password !== "" ) {
+ var authenticated = exports.authenticate( req, req.body.password );
+ if ( authenticated === true ) {
+ res.json( { status: 'success'} );
+ return;
+ }
+ }
+ res.json( {
+ status: 'error',
+ error: 'invalid password'
+ } );
+};
+exports.api_logout_handler = function( req, res ) {
+ req.session.authenticated = false;
+
+ res.json( { status: 'success'} );
+};
+
+var saveDeviceSettings = function() {
+ err = fs.writeFileSync( process.cwd() + "/device.json", JSON.stringify(device_settings, null, 4), 'utf8' );
+ return err;
+};
+
+var reloadDeviceSettings = function() {
+ var settings = {
+ password_hash: '',
+ device_name: '',
+ hostname: '',
+ coder_owner: '',
+ coder_color: ''
+ };
+
+ var loadedsettings = JSON.parse(fs.readFileSync( process.cwd() + "/device.json", 'utf-8' ));
+ settings.password_hash = ( typeof loadedsettings.password_hash !== 'undefined' && loadedsettings.password_hash !== '' ) ? loadedsettings.password_hash : settings.password_hash;
+ settings.device_name = ( typeof loadedsettings.device_name !== 'undefined' && loadedsettings.device_name !== '' ) ? loadedsettings.device_name : settings.device_name;
+ settings.hostname = ( typeof loadedsettings.hostname !== 'undefined' && loadedsettings.hostname !== '' ) ? loadedsettings.hostname : settings.hostname;
+ settings.coder_owner = ( typeof loadedsettings.coder_owner !== 'undefined' && loadedsettings.coder_owner !== '' ) ? loadedsettings.coder_owner : settings.coder_owner;
+ settings.coder_color = ( typeof loadedsettings.coder_color !== 'undefined' && loadedsettings.coder_color !== '' ) ? loadedsettings.coder_color : settings.coder_color;
+
+ device_settings = settings;
+}
+reloadDeviceSettings();
+
+
+var isValidDeviceName = function( name ) {
+ if ( !name || name === '' ) {
+ return false;
+ }
+ //starts with an ascii word char. can contain word char's spaces and '
+ if ( !name.match(/^[a-zA-Z0-9][\w ']*$/) ) {
+ return false;
+ }
+ //ends in an ascii word char
+ if ( !name.match(/[a-zA-Z0-9]$/) ) {
+ return false;
+ }
+ return true;
+};
+var hostnameFromDeviceName = function( name ) {
+ var hostname = name;
+ hostname = hostname.toLowerCase();
+ hostname = hostname.replace(/[^a-z0-9\- ]/g, '');
+ hostname = hostname.replace(/[\- ]+/g,'-');
+ return hostname;
+};
+
+var getPasswordProblem = function( pass ) {
+ if ( !pass || pass === '' ) {
+ return "the password is empty";
+ }
+ if ( pass.length < 6 ) {
+ return "the password should contain at least 6 characters";
+ }
+ if ( !pass.match(/[a-z]/) ||
+ !pass.match(/[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\].*[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\]/) ) {
+ return "your password must contain a lower case letter and at least two upper case letters or numbers";
+ }
+};
+
+var isValidPassword = function( pass ) {
+ if ( !pass || pass === '' ) {
+ return false;
+ }
+ //at least 6 characters
+ if ( pass.length < 6 ) {
+ return false;
+ }
+ //contains lower case
+ if ( !pass.match(/[a-z]/) ) {
+ return false;
+ }
+ //contains two upper case or numbers
+ if ( !pass.match(/[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\].*[A-Z0-9\-\_\.\,\;\:\'\"\[\]\{\}\!\@\#\$\%\^\&\*\(\)\\]/) ) {
+ return false;
+ }
+ return true;
+};
+
+var isValidColor = function( color ) {
+ if ( !color || color === '' ) {
+ return false;
+ }
+ color = color.toLowerCase();
+ if ( !color.match(/^\#[a-f0-9]{6}$/) ) {
+ return false;
+ }
+ return true;
+}
+
+
+
+
diff --git a/coder-base/apps/auth/meta.json b/coder-apps/common/auth/app/meta.json
similarity index 100%
rename from coder-base/apps/auth/meta.json
rename to coder-apps/common/auth/app/meta.json
diff --git a/coder-base/static/apps/auth/css/index.css b/coder-apps/common/auth/static/css/index.css
similarity index 100%
rename from coder-base/static/apps/auth/css/index.css
rename to coder-apps/common/auth/static/css/index.css
diff --git a/coder-base/static/apps/auth/js/index.js b/coder-apps/common/auth/static/js/index.js
similarity index 100%
rename from coder-base/static/apps/auth/js/index.js
rename to coder-apps/common/auth/static/js/index.js
diff --git a/coder-base/views/apps/coderlib/index.html b/coder-apps/common/auth/static/media/.gitignore
similarity index 100%
rename from coder-base/views/apps/coderlib/index.html
rename to coder-apps/common/auth/static/media/.gitignore
diff --git a/coder-apps/common/auth/views/index.html b/coder-apps/common/auth/views/index.html
new file mode 100644
index 00000000..d2da0a2a
--- /dev/null
+++ b/coder-apps/common/auth/views/index.html
@@ -0,0 +1,108 @@
+
+
+
+ Coder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{device_name}}
+
+
+
+
+
Welcome to Coder
+
Enter your Coder password to get coding.
+
+ Password
+
+
+
Let's Code
+
+
+
+
+
You Are Signed Out
+
To get back to coding, enter your Coder password.
+
+ Password
+
+
+
Let's Code
+
+
+
+
+
Welcome to Coder
+
First, let's give your Coder a name.
+
+ Your Coder's Name
+
+
+
OK. Save My Coder's Name
+
+
+
+
+
+
Protect Your Coder
+
Set a password here to make this Coder yours.
+
+ My Password
+
+
+
+ My Password, Again
+
+
+
Save My Password
+
+
+
+
+
Change Your Coder Password
+
Confirm your current password, then choose a new one to secure your Coder.
+
+ Old Password
+
+
+
+ New Password
+
+
+
+ New Password, Again
+
+
+
Save My Password
+
Cancel
+
+
+
+
+
+
+
+
+
+
+
diff --git a/coder-base/apps/boilerplate/app.js b/coder-apps/common/boilerplate/app/app.js
similarity index 100%
rename from coder-base/apps/boilerplate/app.js
rename to coder-apps/common/boilerplate/app/app.js
diff --git a/coder-base/apps/boilerplate/meta.json b/coder-apps/common/boilerplate/app/meta.json
similarity index 100%
rename from coder-base/apps/boilerplate/meta.json
rename to coder-apps/common/boilerplate/app/meta.json
diff --git a/coder-base/static/apps/boilerplate/css/index.css b/coder-apps/common/boilerplate/static/css/index.css
similarity index 100%
rename from coder-base/static/apps/boilerplate/css/index.css
rename to coder-apps/common/boilerplate/static/css/index.css
diff --git a/coder-base/static/apps/boilerplate/js/index.js b/coder-apps/common/boilerplate/static/js/index.js
similarity index 100%
rename from coder-base/static/apps/boilerplate/js/index.js
rename to coder-apps/common/boilerplate/static/js/index.js
diff --git a/coder-apps/common/boilerplate/static/media/.gitignore b/coder-apps/common/boilerplate/static/media/.gitignore
new file mode 100644
index 00000000..e69de29b
diff --git a/coder-base/views/apps/boilerplate/index.html b/coder-apps/common/boilerplate/views/index.html
similarity index 100%
rename from coder-base/views/apps/boilerplate/index.html
rename to coder-apps/common/boilerplate/views/index.html
diff --git a/coder-base/apps/coder/app.js b/coder-apps/common/coder/app/app.js
similarity index 100%
rename from coder-base/apps/coder/app.js
rename to coder-apps/common/coder/app/app.js
diff --git a/coder-base/apps/coder/meta.json b/coder-apps/common/coder/app/meta.json
similarity index 100%
rename from coder-base/apps/coder/meta.json
rename to coder-apps/common/coder/app/meta.json
diff --git a/coder-base/static/apps/coder/css/index.css b/coder-apps/common/coder/static/css/index.css
similarity index 100%
rename from coder-base/static/apps/coder/css/index.css
rename to coder-apps/common/coder/static/css/index.css
diff --git a/coder-apps/common/coder/static/js/index.js b/coder-apps/common/coder/static/js/index.js
new file mode 100644
index 00000000..c6ac1a67
--- /dev/null
+++ b/coder-apps/common/coder/static/js/index.js
@@ -0,0 +1,454 @@
+/**
+ * Coder for Raspberry Pi
+ * A simple platform for experimenting with web stuff.
+ * http://goo.gl/coder
+ *
+ * Copyright 2013 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var metadata;
+
+$(document).ready( function() {
+
+ Coder.listApps( buildAppList );
+
+ $('#addapp_button').click( function(e){
+ $(this).hide();
+ $("#createform").show();
+ });
+ $('#createform .cancel').click( function(e){
+ $("#createform").hide();
+ $("#addapp_button").show();
+ });
+ $('#createform .submit').click( createAppClicked );
+
+ $('#import_file').on('change', handleFileImport );
+
+ $('#createform .formfield.textinput .label').click( focusTextInput );
+ $('#createform .formfield.textinput input').click( focusTextInput );
+ $('#createform .formfield.textinput input').focus( hideTextLabel );
+ $('#createform .formfield.textinput input').blur( onBlurTextInput );
+
+ $("#createform .colorchit").click( selectAppColor );
+ activateCurrentColor();
+
+
+ $("#settings_button").click( toggleSettings );
+ $("#settingscontainer .changepass").click( function() {
+ window.location.href="http://github.com/app/auth/changepassword";
+ });
+
+ $("#settingscontainer .colorchit").click( selectCoderColor );
+ activateCurrentCoderColor();
+ updateSettingsData();
+ $("#settingscontainer input").on('change', checkChangedSettings );
+ $("#settingscontainer input").on('keydown', function() { setTimeout( checkChangedSettings, 0); } );
+ $("#settingscontainer .cancel").click( revertSettings );
+ $("#settingscontainer .save").click( saveSettings );
+
+ $("#settingscontainer .logout").click( function() {
+ window.location.href="http://github.com/app/auth/logout";
+ });
+
+ if ( typeof getParams['firstuse'] !== 'undefined' ) {
+ setTimeout( function(){
+ buildIntroduction();
+ }, 400 );
+ } else {
+ $('#introduction').css('display','none');
+ }
+});
+
+
+var buildIntroduction = function() {
+ $('#introduction').css({
+ 'display': 'none',
+ 'visibility': 'visible'
+ }).fadeIn( 'slow', function() {
+ setTimeout( function() {
+ $('#myapps_tip').css({'visibility':'visible'}).hide().fadeIn();
+ }, 1000);
+ setTimeout( function() {
+ $('#newapp_tip').css({'visibility':'visible'}).hide().fadeIn();
+ }, 2000);
+ setTimeout( function() {
+ $('#settings_tip').css({'visibility':'visible'}).hide().fadeIn();
+ }, 3000);
+ });
+ $('.gotit').click( function() {
+ $('#introduction').fadeOut(function() {
+ $(this).hide();
+ });
+ });
+};
+
+
+
+
+
+var revertSettings = function() {
+ activateCurrentCoderColor();
+ updateSettingsData();
+ checkChangedSettings();
+};
+
+var updateSettingsData = function( ) {
+ $('#coder_name').val( device_name );
+ $('#coder_ownername').val( coder_owner );
+};
+
+var hideTextLabel = function() {
+ $(this).parent().find('.label').hide();
+};
+var focusTextInput = function() {
+ $(this).parent().find('input').focus();
+};
+var onBlurTextInput = function() {
+ if ( $(this).val() == "" ) {
+ $(this).parent().find('.label').show();
+ }
+};
+var thefile = null;
+var handleFileImport = function( ev ) {
+ var files = ev.target.files;
+
+ if ( files && files.length > 0 ) {
+ var importfile = files[0];
+
+ //console.log( importfile );
+ if (!importfile.type.match('application/zip')) {
+ alert('This doesn\'t appear to be a Coder project zip file');
+ return false;
+ }
+ thefile = importfile;
+
+ var fdata = new FormData();
+ fdata.append( 'import_file', thefile );
+ fdata.append( 'test', 'foo' );
+
+ $.ajax({
+ url: '/app/coder/api/app/import',
+ type: 'POST',
+ contentType: false,
+ processData: false,
+ cache: false,
+ data: fdata,
+ success: function( data ) {
+ //console.log('upload returned');
+ //console.log(data);
+ if ( data.status === 'success' ) {
+ var newappid = data.appname;
+ window.location.href = '/app/editor/edit/' + encodeURIComponent(newappid);
+ } else if ( typeof data.error !== 'undefined' ) {
+ alert( data.error );
+ }
+ }
+ });
+
+
+ /*
+ var reader = new FileReader();
+ // Closure to capture the file information.
+ reader.onload = (function(theFile) {
+ return function(e) {
+ // Render thumbnail.
+ var span = document.createElement('span');
+ span.innerHTML = [''].join('');
+ document.getElementById('list').insertBefore(span, null);
+ };
+ })(f);
+
+ reader.readAsDataURL(f);
+ */
+ }
+};
+
+
+var settingson = false;
+var toggleSettings = function() {
+ settingson = !settingson;
+ enableSettings( settingson );
+};
+var enableSettings = function( on ) {
+ settingson = on;
+ if ( settingson ) {
+ $("body").addClass('settingsEnabled');
+ } else {
+ $("body").removeClass('settingsEnabled');
+ }
+};
+
+
+var activateCurrentCoderColor = function() {
+ var current = coder_color;
+ $("#coder_nav").css('background-color', current);
+ $("#settingscontainer .colorchit").each( function() {
+ $this = $(this);
+ $this.removeClass('active');
+
+ if ( rgb2hex($this.css('background-color')) === current ) {
+ $this.addClass('active');
+ }
+ });
+
+};
+
+var selectCoderColor = function() {
+ $this = $(this);
+ $("#settingscontainer .colorchit").removeClass('active');
+ $this.addClass('active');
+ checkChangedSettings();
+};
+
+var device_changed = false;
+var owner_changed = false;
+var color_changed = false;
+var checkChangedSettings = function() {
+ var changed = false;
+ device_changed = false;
+ owner_changed = false;
+ color_changed = false;
+
+ if ( $('#coder_name').val() !== device_name ) {
+ changed = device_changed = true;
+ }
+ if ( $('#coder_ownername').val() !== coder_owner ) {
+ changed = owner_changed = true;
+ }
+ var $selectedcolor = $("#settingscontainer .colorchit.active").first();
+ if ( $selectedcolor.get(0) && rgb2hex($selectedcolor.css('background-color')) !== coder_color.toLowerCase() ) {
+ changed = color_changed = true;
+ }
+
+ if ( changed ) {
+ $('#settingscontainer').addClass('changed');
+ } else {
+ $('#settingscontainer').removeClass('changed');
+ }
+};
+
+var saveSettings = function() {
+
+ var saveDeviceName = function(callback) {
+ if ( !device_changed ) {
+ callback();
+ return;
+ }
+ $.post('/app/auth/api/devicename/set',
+ { 'device_name': $('#coder_name').val() },
+ function(d) {
+ //console.log( d );
+ if ( d.status === 'success' ) {
+ device_name = d.device_name;
+ $("#coder_logo").text( device_name );
+ }
+ callback();
+ }
+ );
+ };
+
+ var saveOwnerName = function(callback) {
+ if ( !owner_changed ) {
+ callback();
+ return;
+ }
+ $.post('/app/auth/api/coderowner/set',
+ { 'coder_owner': $('#coder_ownername').val() },
+ function(d) {
+ //console.log( d );
+ if ( d.status === 'success' ) {
+ coder_owner = d.coder_owner;
+ }
+ callback();
+ }
+ );
+ };
+
+ var saveCoderColor = function(callback) {
+ if ( !color_changed ) {
+ callback();
+ return;
+ }
+ var $selectedcolor = $("#settingscontainer .colorchit.active").first();
+ if ( !$selectedcolor.get(0) ) {
+ callback();
+ return;
+ }
+ var hexcolor = rgb2hex($selectedcolor.css('background-color'));
+
+
+ $.post('/app/auth/api/codercolor/set',
+ { 'coder_color': hexcolor },
+ function(d) {
+ //console.log( d );
+ if ( d.status === 'success' ) {
+ coder_color = d.coder_color;
+ $("#coder_nav").css('background-color', coder_color);
+ }
+ callback();
+ }
+ );
+ };
+
+ saveDeviceName(function() {
+ saveOwnerName(function() {
+ saveCoderColor(function() {
+ checkChangedSettings();
+ });
+ });
+ });
+
+};
+
+var buildAppList = function(apps){
+
+
+ //get the app color from our own app (appname is set globally in template)
+ metadata = apps[appname].metadata;
+ $('.userbgcolor').css('background-color', metadata.color);
+
+ var $apptmpl = $('#appitem_template').clone();
+ $apptmpl.attr('id', '').css('display','');
+
+ var launchApp = function( appname ) {
+ return function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ window.location.href = '/app/' + encodeURIComponent(appname);
+ };
+ };
+ var editApp = function( appname ) {
+ return function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ window.location.href = '/app/editor/edit/' + encodeURIComponent(appname);
+ };
+ };
+
+
+
+ //Sort the apps by more recently modified
+ var sortedapps = [];
+ for ( var k in apps ) {
+ sortedapps.push( apps[k] );
+ }
+ sortedapps.sort( function(a,b) {
+ if ( a.ctime < b.ctime ) {
+ return 1;
+ } else if ( b.ctime < a.ctime ) {
+ return -1;
+ } else {
+ return 0;
+ }
+ });
+
+ for ( var x=0; x
+
+
+ Coder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+