Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
18
gaia/tv_apps/smart-system/fxa/test/marionette/.jshintrc
Executable file
18
gaia/tv_apps/smart-system/fxa/test/marionette/.jshintrc
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"extends": "../../../../../.jshintrc",
|
||||
"node": true,
|
||||
"predef": [
|
||||
"suite",
|
||||
"test",
|
||||
"setup",
|
||||
"teardown",
|
||||
"suiteSetup",
|
||||
"suiteTeardown",
|
||||
"marionette",
|
||||
"marionetteScriptFinished",
|
||||
"require",
|
||||
"define",
|
||||
"requireApp",
|
||||
"sinon"
|
||||
]
|
||||
}
|
||||
55
gaia/tv_apps/smart-system/fxa/test/marionette/fxa_launch_test.js
Executable file
55
gaia/tv_apps/smart-system/fxa/test/marionette/fxa_launch_test.js
Executable file
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
var FxA = require('./lib/fxa');
|
||||
|
||||
marionette('Firefox Accounts Launch Tests', function() {
|
||||
var app,
|
||||
selectors,
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'focusmanager.testmode': true
|
||||
},
|
||||
settings: {
|
||||
'ftu.manifestURL': FxA.FTU_ORIGIN + '/manifest.webapp'
|
||||
},
|
||||
apps: {
|
||||
'test-fxa-client.gaiamobile.org': __dirname + '/test-fxa-client'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
app = new FxA(client);
|
||||
selectors = FxA.Selectors;
|
||||
});
|
||||
|
||||
//If we can enter email on first screen, that should prove successful launch
|
||||
suite('Should launch FxA flow from FxA-consuming apps:', function () {
|
||||
test('Settings app', function () {
|
||||
app.launch(FxA.SETTINGS_ORIGIN);
|
||||
app.runSettingsMenu();
|
||||
app.enterEmailNew();
|
||||
});
|
||||
|
||||
test('UITest app', function () {
|
||||
app.launch(FxA.UITEST_ORIGIN);
|
||||
app.runUITestMenu();
|
||||
app.enterEmailNew();
|
||||
});
|
||||
|
||||
test('FTU menu', function () {
|
||||
app.launch(FxA.FTU_ORIGIN);
|
||||
app.runFTUMenu();
|
||||
app.enterEmailNew();
|
||||
});
|
||||
|
||||
// This is an old version which uses the IAC API.
|
||||
// TODO: INTERMITTENT failures?
|
||||
test.skip('test-fxa-client app', function () {
|
||||
app.launch(FxA.TEST_FXA_CLIENT_ORIGIN);
|
||||
app.runFxAClientTestMenu();
|
||||
app.enterEmailNew();
|
||||
});
|
||||
});
|
||||
});
|
||||
62
gaia/tv_apps/smart-system/fxa/test/marionette/fxa_screen_flow_test.js
Executable file
62
gaia/tv_apps/smart-system/fxa/test/marionette/fxa_screen_flow_test.js
Executable file
|
|
@ -0,0 +1,62 @@
|
|||
'use strict';
|
||||
|
||||
var FxA = require('./lib/fxa'),
|
||||
FxAUser = require('./lib/fxa_user'),
|
||||
Server = require('./lib/server'),
|
||||
config = require('./lib/config.json');
|
||||
|
||||
marionette('Firefox Accounts Screen Flow Test (UITest app)', function() {
|
||||
var app,
|
||||
selectors,
|
||||
server,
|
||||
fxaUser,
|
||||
client = marionette.client({
|
||||
profile: {
|
||||
prefs: {
|
||||
'focusmanager.testmode': true,
|
||||
'identity.fxaccounts.auth.uri': 'http://' +
|
||||
config.SERVER_HOST + ':' +
|
||||
config.SERVER_PORT + '/' +
|
||||
config.SERVER_PATH
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setup(function(done) {
|
||||
fxaUser = new FxAUser();
|
||||
app = new FxA(client);
|
||||
Server.create(FxA.SERVER_ARGS, function (err, _server) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
server = _server;
|
||||
done();
|
||||
});
|
||||
selectors = FxA.Selectors;
|
||||
app.launch(FxA.UITEST_ORIGIN);
|
||||
app.runUITestMenu();
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
server.stop();
|
||||
});
|
||||
|
||||
test('should walk screen flow for new user', function () {
|
||||
app.enterEmailNew();
|
||||
app.clickNext();
|
||||
app.enterCOPPANew();
|
||||
app.clickNext();
|
||||
app.enterPasswordNew();
|
||||
app.clickNext();
|
||||
app.clickDone();
|
||||
});
|
||||
|
||||
test('should walk screen flow for existing user', function () {
|
||||
app.enterEmailExisting();
|
||||
app.clickNext();
|
||||
app.enterPasswordExisting();
|
||||
app.clickNext();
|
||||
app.clickDone();
|
||||
});
|
||||
});
|
||||
17
gaia/tv_apps/smart-system/fxa/test/marionette/lib/config.json
Executable file
17
gaia/tv_apps/smart-system/fxa/test/marionette/lib/config.json
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"MARIONETTE_TIMEOUT": 20000,
|
||||
"USER_NEW": 0,
|
||||
"USER_EXISTING": 1,
|
||||
"USER_EXISTING_EMAIL": "kilroy_exists",
|
||||
"USER_EXISTING_PW": "123456789",
|
||||
"USERNAME_LEN": "24",
|
||||
"USER_NEW_PW": "123456789",
|
||||
"PASSWORD_HASH": "059b7beebaf4824e5395fb9eba6e8424b6ee27b43675130608502790e4af2178",
|
||||
"MAIL_HOST": "restmail.net",
|
||||
"SERVER_HOST": "localhost",
|
||||
"SERVER_PORT": 8081,
|
||||
"SERVER_PATH": "v1",
|
||||
"AUTH_SERVER_URL": "https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format",
|
||||
"DEBUG": false
|
||||
}
|
||||
|
||||
235
gaia/tv_apps/smart-system/fxa/test/marionette/lib/fxa.js
Executable file
235
gaia/tv_apps/smart-system/fxa/test/marionette/lib/fxa.js
Executable file
|
|
@ -0,0 +1,235 @@
|
|||
'use strict';
|
||||
|
||||
var FxAUser = require('./fxa_user'),
|
||||
config = require('./config.json');
|
||||
|
||||
/**
|
||||
* Abstraction around FxA app.
|
||||
* 'Entrance point' app URL is passed in since FxA acts more like a
|
||||
* component than a standalone app
|
||||
* (launched by Settings, Marketplace, FTU, FMD, dev_apps, etc.)
|
||||
*
|
||||
* @param client
|
||||
* @constructor
|
||||
*/
|
||||
function FxA(client) {
|
||||
this.config = config;
|
||||
this.fxaUser = new FxAUser();
|
||||
this.client = client.scope({ searchTimeout: config.MARIONETTE_TIMEOUT});
|
||||
}
|
||||
|
||||
FxA.SETTINGS_ORIGIN = 'app://settings.gaiamobile.org';
|
||||
FxA.UITEST_ORIGIN = 'app://uitest.gaiamobile.org';
|
||||
FxA.TEST_FXA_CLIENT_ORIGIN = 'app://test-fxa-client.gaiamobile.org';
|
||||
FxA.FTU_ORIGIN = 'app://ftu.gaiamobile.org';
|
||||
FxA.SERVER_PATH = 'http://' +
|
||||
config.SERVER_HOST + ':' +
|
||||
config.SERVER_PORT + '/' +
|
||||
config.SERVER_PATH;
|
||||
FxA.SERVER_ARGS = [
|
||||
config.SERVER_HOST,
|
||||
config.SERVER_PORT,
|
||||
config.SERVER_PATH
|
||||
];
|
||||
|
||||
FxA.COPPA_YEAR = new Date().getFullYear() - 13;
|
||||
|
||||
FxA.Selectors = {
|
||||
body: 'body',
|
||||
bodyReady: 'body .view-body',
|
||||
// dev_apps/uitest
|
||||
apiFxaFrame: '#test-iframe',
|
||||
fxaFrame: '#fxa-iframe',
|
||||
tabAPI: '#API',
|
||||
fxaButton: '#mozId-fxa',
|
||||
requestButton: '#request',
|
||||
// dev_apps/test-fxa-client
|
||||
tabOpenFlow: '#openFlow',
|
||||
// apps/settings
|
||||
menuItemFxa: '#menuItem-fxa',
|
||||
menuItemFmd: '#menuItem-findmydevice',
|
||||
fxaLogin: '#fxa-login',
|
||||
fmdLogin: '#findmydevice-login',
|
||||
fxaCancelAccountConfirmation: '#fxa-cancel-confirmation',
|
||||
// apps/ftu
|
||||
forward: '#forward',
|
||||
createAccountOrLogin: '#fxa-create-account',
|
||||
// apps/findmydevice
|
||||
emailInput: '#fxa-email-input',
|
||||
fxaForgotPassword: 'fxa-forgot-password',
|
||||
pwInput: '#fxa-pw-input',
|
||||
//COPPA (age-restriction menu no longer appears,
|
||||
// but password input tag is still different)
|
||||
pwInputPostCOPPA: '#fxa-pw-set-input',
|
||||
pwSetInput: '#fxa-pw-set-input',
|
||||
pwRefresh: '#fxa-pw-input-refresh',
|
||||
COPPAElementId: '#fxa-coppa',
|
||||
COPPASelectId: '#fxa-age-select',
|
||||
COPPAOptionVal: FxA.COPPA_YEAR + ' or earlier',
|
||||
COPPAOptionValToFail: FxA.COPPA_YEAR.toString(),
|
||||
moduleNext: '#fxa-module-next',
|
||||
moduleDone: '#fxa-module-done',
|
||||
errorOK: '#fxa-error-ok'
|
||||
};
|
||||
|
||||
FxA.prototype = {
|
||||
/**
|
||||
* Launches FxA app and focuses on frame.
|
||||
*/
|
||||
launch: function (origin) {
|
||||
// do unless FTU
|
||||
if (origin.search('ftu') === -1) {
|
||||
this.client.apps.launch(origin);
|
||||
}
|
||||
this.client.apps.switchToApp(origin);
|
||||
},
|
||||
|
||||
enterInput: function (inputId, inputString) {
|
||||
this.client.helper
|
||||
.waitForElement(inputId)
|
||||
.sendKeys(inputString);
|
||||
},
|
||||
|
||||
enterCOPPANew: function () {
|
||||
var sel = FxA.Selectors.COPPASelectId;
|
||||
var inputString = FxA.Selectors.COPPAOptionVal;
|
||||
this.client.helper.tapSelectOption(sel, inputString);
|
||||
},
|
||||
|
||||
enterEmailNew: function () {
|
||||
var sel = FxA.Selectors.emailInput;
|
||||
var inputString = this.fxaUser.email(config.USER_NEW);
|
||||
this.client.helper.fillInputField(sel, inputString);
|
||||
},
|
||||
enterPasswordNew: function () {
|
||||
var sel = FxA.Selectors.pwInputPostCOPPA;
|
||||
var inputString = this.fxaUser.password(config.USER_NEW);
|
||||
this.client.helper.fillInputField(sel, inputString);
|
||||
},
|
||||
enterEmailExisting: function () {
|
||||
var sel = FxA.Selectors.emailInput;
|
||||
var inputString = this.fxaUser.email(config.USER_EXISTING);
|
||||
this.client.helper.fillInputField(sel, inputString);
|
||||
},
|
||||
enterPasswordExisting: function () {
|
||||
var sel = FxA.Selectors.pwInput;
|
||||
var inputString = this.fxaUser.password(config.USER_EXISTING);
|
||||
this.client.helper.fillInputField(sel, inputString);
|
||||
},
|
||||
onClick: function(searchSelector) {
|
||||
var element = this.client.findElement(searchSelector);
|
||||
this.client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
clickNext: function() {
|
||||
var element = this.client.findElement(FxA.Selectors.moduleNext);
|
||||
var client = this.client;
|
||||
|
||||
client.waitFor(function () {
|
||||
return client.findElement(FxA.Selectors.moduleNext)
|
||||
.scriptWith(function (el) {
|
||||
return el.getAttribute('disabled') !== 'disabled';
|
||||
});
|
||||
});
|
||||
|
||||
client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
clickDone: function() {
|
||||
var element = this.client.findElement(FxA.Selectors.moduleDone);
|
||||
this.client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
clickTabOpenFlow: function() {
|
||||
var element = this.client.findElement(FxA.Selectors.tabOpenFlow);
|
||||
this.client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
clickFxaLogin: function() {
|
||||
var element = this.client.findElement(FxA.Selectors.fxaLogin);
|
||||
this.client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
clickMenuItemFxa: function() {
|
||||
var element = this.client.findElement(FxA.Selectors.menuItemFxa);
|
||||
this.client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
clickRequestButton: function() {
|
||||
var element = this.client.findElement(FxA.Selectors.requestButton);
|
||||
this.client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
clickTabAPI: function() {
|
||||
var element = this.client.findElement(FxA.Selectors.tabAPI);
|
||||
this.client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
clickFxaButton: function() {
|
||||
var element = this.client.findElement(FxA.Selectors.fxaButton);
|
||||
this.client.helper
|
||||
.waitForElement(element)
|
||||
.tap();
|
||||
},
|
||||
switchFrame: function(frameId) {
|
||||
this.client.switchToFrame();
|
||||
var frame = this.client.findElement(frameId);
|
||||
this.client.switchToFrame(frame);
|
||||
},
|
||||
switchFrameDirect: function(frameId) {
|
||||
var frame = this.client.findElement(frameId);
|
||||
this.client.switchToFrame(frame);
|
||||
},
|
||||
clickThruPanel: function(panelId, buttonId) {
|
||||
if (panelId === '#wifi') {
|
||||
// The wifi panel will bring up a screen to show it is scanning for
|
||||
// networks. Not waiting for this to clear will blow test timing
|
||||
// and cause things to fail.
|
||||
this.client.helper.waitForElementToDisappear('#loading-overlay');
|
||||
}
|
||||
// waitForElement is used to make sure animations and page changes have
|
||||
// finished, and that the panel is displayed.
|
||||
this.client.helper.waitForElement(panelId);
|
||||
|
||||
if (buttonId) {
|
||||
var button = this.client.helper.waitForElement(buttonId);
|
||||
button.click();
|
||||
}
|
||||
},
|
||||
runSettingsMenu: function() {
|
||||
this.clickMenuItemFxa();
|
||||
this.clickFxaLogin();
|
||||
this.switchFrame(FxA.Selectors.fxaFrame);
|
||||
},
|
||||
runUITestMenu: function() {
|
||||
this.clickTabAPI();
|
||||
this.clickFxaButton();
|
||||
this.switchFrameDirect(FxA.Selectors.apiFxaFrame);
|
||||
this.clickRequestButton();
|
||||
this.switchFrame(FxA.Selectors.fxaFrame);
|
||||
},
|
||||
runFTUMenu: function() {
|
||||
this.clickThruPanel('#languages', '#forward');
|
||||
this.clickThruPanel('#wifi', '#forward');
|
||||
this.clickThruPanel('#date_and_time', '#forward');
|
||||
this.clickThruPanel('#geolocation', '#forward');
|
||||
this.clickThruPanel('#import_contacts', '#forward');
|
||||
this.clickThruPanel('#firefox_accounts',
|
||||
FxA.Selectors.createAccountOrLogin);
|
||||
this.switchFrame(FxA.Selectors.fxaFrame);
|
||||
},
|
||||
runFxAClientTestMenu: function() {
|
||||
this.clickTabOpenFlow();
|
||||
this.switchFrame(FxA.Selectors.fxaFrame);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = FxA;
|
||||
54
gaia/tv_apps/smart-system/fxa/test/marionette/lib/fxa_user.js
Executable file
54
gaia/tv_apps/smart-system/fxa/test/marionette/lib/fxa_user.js
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
'use strict';
|
||||
|
||||
var config = require('./config.json');
|
||||
|
||||
/**
|
||||
* FxA user handler for email, password & string generations
|
||||
* @constructor
|
||||
*/
|
||||
function FxAUser() {
|
||||
}
|
||||
|
||||
FxAUser.prototype = {
|
||||
_randString: function(len, charSet){
|
||||
charSet = charSet || 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
var rand = '';
|
||||
for (var i = 0; i < len; i++) {
|
||||
var randomPoz = Math.floor(Math.random() * charSet.length);
|
||||
rand += charSet.substring(randomPoz, randomPoz + 1);
|
||||
}
|
||||
return rand;
|
||||
},
|
||||
|
||||
get _uniqueUserName() {
|
||||
return this._randString(config.USERNAME_LEN);
|
||||
},
|
||||
|
||||
/**
|
||||
* @TODO bug 1052267
|
||||
* add ability to generate variety of "invalid" email strings
|
||||
*/
|
||||
email: function(userType) {
|
||||
switch(userType) {
|
||||
case config.USER_NEW:
|
||||
return this._uniqueUserName + '@' + config.MAIL_HOST;
|
||||
default:
|
||||
return config.USER_EXISTING_EMAIL + '@' + config.MAIL_HOST;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @TODO bug 1052267
|
||||
* add ability to generate variety of "invalid" password strings
|
||||
*/
|
||||
password: function(userType) {
|
||||
switch(userType) {
|
||||
case config.USER_NEW:
|
||||
return config.USER_NEW_PW;
|
||||
default:
|
||||
return config.USER_EXISTING_PW;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = FxAUser;
|
||||
39
gaia/tv_apps/smart-system/fxa/test/marionette/lib/server.js
Executable file
39
gaia/tv_apps/smart-system/fxa/test/marionette/lib/server.js
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
function Server(child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
Server.prototype = {
|
||||
/**
|
||||
* Sends signal to stop child process and stop server.
|
||||
*
|
||||
* TODO: Bug 1056186:
|
||||
* [FxA] Create unit tests for Firefox Accounts mock server process
|
||||
*/
|
||||
stop: function() {
|
||||
this.child.kill('SIGTERM');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Spawn the child process where the FxA mock server lives.
|
||||
*
|
||||
* @param args - [ host, port, path ]
|
||||
* @param callback
|
||||
*/
|
||||
function create(args, callback) {
|
||||
var child = require('child_process')
|
||||
.fork(__dirname + '/server_mock_fxa.js', args)
|
||||
.on('message', function(data) {
|
||||
if (Array.isArray(data) && data[0] === 'start') {
|
||||
callback(null, new Server(child));
|
||||
}
|
||||
})
|
||||
.on('error', function (err) {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
Server.create = create;
|
||||
module.exports = Server;
|
||||
434
gaia/tv_apps/smart-system/fxa/test/marionette/lib/server_mock_fxa.js
Executable file
434
gaia/tv_apps/smart-system/fxa/test/marionette/lib/server_mock_fxa.js
Executable file
|
|
@ -0,0 +1,434 @@
|
|||
'use strict';
|
||||
|
||||
var restify = require('restify'),
|
||||
ecstatic = require('ecstatic'),
|
||||
config = require('./config.json');
|
||||
|
||||
var server = restify.createServer({
|
||||
name: 'Mock Firefox Accounts Server'
|
||||
});
|
||||
|
||||
server.hostname = process.argv[2];
|
||||
server.port = process.argv[3];
|
||||
server.version = process.argv[4];
|
||||
|
||||
process.on('uncaughtException', gracefulShutdown);
|
||||
server.on('uncaughtException', gracefulShutdown);
|
||||
|
||||
function shutdown(cb) {
|
||||
try {
|
||||
server.close(cb);
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function gracefulShutdown(err) {
|
||||
if (err) {
|
||||
console.error(err.stack);
|
||||
}
|
||||
shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* authPW = 123456789
|
||||
* client accepts any hex Token the server kindly grants it
|
||||
* Note: other user types could be added: i.e. verified user
|
||||
*/
|
||||
var account = {
|
||||
'new': {
|
||||
'authPW': config.PASSWORD_HASH,
|
||||
'uid': randomString(32),
|
||||
'sessionToken': randomString(64),
|
||||
'keyFetchToken': randomString(64),
|
||||
'passwordChangeToken': randomString(64),
|
||||
'verified': false,
|
||||
'authAt': Date.now()
|
||||
},
|
||||
|
||||
'exists': {
|
||||
'email': config.USER_EXISTING_EMAIL + '@' + config.MAIL_HOST,
|
||||
'authPW': config.PASSWORD_HASH,
|
||||
'uid': randomString(32),
|
||||
'sessionToken': randomString(64),
|
||||
'keyFetchToken': randomString(64),
|
||||
'passwordChangeToken': randomString(64),
|
||||
'verified': false,
|
||||
'authAt': Date.now()
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mock Firefox Accounts Server
|
||||
*
|
||||
* Purpose:
|
||||
* Mimic behavior of FxA server v1
|
||||
* (SHA: 29dc9abbacb3fe1b6de763f3c7bd85e63215297c)
|
||||
* with mostly 'canned' responses
|
||||
* Some APIs (i.e. for authentication) provide limited logical checking
|
||||
* for testing B2G
|
||||
*
|
||||
* Reference
|
||||
* https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md
|
||||
*/
|
||||
var Server = {
|
||||
|
||||
//set to true for verbose logging
|
||||
debug: config.DEBUG || false,
|
||||
|
||||
// allows for terminating process directly when calling server standalone
|
||||
// when calling as child process, use child.kill() from parent
|
||||
stop: function() {
|
||||
gracefulShutdown();
|
||||
console.log('SERVER STOPPED');
|
||||
},
|
||||
|
||||
start: function() {
|
||||
server.use(restify.acceptParser(server.acceptable));
|
||||
server.use(restify.queryParser());
|
||||
server.use(restify.bodyParser());
|
||||
server.use(ecstatic({ root: __dirname + '/' }));
|
||||
server.get('/', ecstatic({ root: __dirname }));
|
||||
server.listen(server.port, function() {
|
||||
var debug = Server.debug || false;
|
||||
if (debug) {
|
||||
console.log(' %s running on port: %s', server.name, server.port);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
(function(err, port) {
|
||||
Server.start();
|
||||
process.send(['start']);
|
||||
})();
|
||||
|
||||
// handle process messages
|
||||
process.on('message', function(data) {
|
||||
switch (data) {
|
||||
case 'stop':
|
||||
console.log('STOPPING MOCK SERVER');
|
||||
Server.stop();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
server.post('/v1/account/create', postAccountCreate);
|
||||
server.get('/v1/account/status', getAccountStatus);
|
||||
server.get('/v1/account/devices', getAccountDevices);
|
||||
server.get('/v1/account/keys', getAccountKeys);
|
||||
server.post('/v1/account/reset', respondEmpty);
|
||||
server.post('/v1/account/destroy', respondEmpty);
|
||||
server.post('/v1/account/login', postAccountLogin);
|
||||
server.get('/v1/session/status', respondEmpty);
|
||||
server.post('/v1/session/destroy', respondEmpty);
|
||||
server.get('/v1/recovery_email/status', getRecoveryEmailStatus);
|
||||
server.post('/v1/recovery_email/resend_code', respondEmpty);
|
||||
server.post('/v1/recovery_email/verify_code', respondEmpty);
|
||||
server.post('/v1/certificate/sign', postCertificateSign);
|
||||
server.post('/v1/password/change/start', postPasswordChangeStart);
|
||||
server.post('/v1/password/change/finish', respondEmpty);
|
||||
server.post('/v1/password/forgot/send_code', postPasswordForgotSendCode);
|
||||
server.post('/v1/password/forgot/resend_code', postPasswordForgotResendCode);
|
||||
server.post('/v1/password/forgot/verify_code', postPasswordForgotVerifyCode);
|
||||
server.get('/v1/forgot/status', getPasswordForgotStatus);
|
||||
server.post('/v1/get_random_bytes', postGetRandomBytes);
|
||||
|
||||
//catch any undefined requests
|
||||
server.get(/^\/([a-zA-Z0-9_\.~-]+)\/(.*)/, anyUndefined);
|
||||
server.post(/^\/([a-zA-Z0-9_\.~-]+)\/(.*)/, anyUndefined);
|
||||
|
||||
/************************************
|
||||
* API: Account
|
||||
************************************/
|
||||
|
||||
function postAccountCreate(req,res,next) {
|
||||
var accountSelected = getAccountType(req.body.email);
|
||||
var jsonResponse = getRespAccountCreate(accountSelected);
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
function getAccountStatus(req,res,next) {
|
||||
var jsonResponse = { 'exists': false };
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
function getAccountDevices(req,res,next) {
|
||||
var jsonResponse = {
|
||||
'devices': [
|
||||
{
|
||||
'id': '4c352927-cd4f-4a4a-a03d-7d1893d950b8',
|
||||
'type': 'computer',
|
||||
'name': 'Foxys Macbook'
|
||||
}
|
||||
]
|
||||
};
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
function getAccountKeys(req,res,next) {
|
||||
var jsonResponse = {
|
||||
'bundle': randomString(256)
|
||||
};
|
||||
printLog('GET /account/keys', jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
/************************************
|
||||
* API: Authentication
|
||||
************************************/
|
||||
|
||||
function postAccountLogin(req,res,next) {
|
||||
var jsonResponse;
|
||||
var accountSelected = getAccountType(req.body.email);
|
||||
|
||||
if (req.body.email === account.exists.email) {
|
||||
if (req.body.authPW === account.exists.authPW) {
|
||||
jsonResponse = getRespAccountLogin(accountSelected);
|
||||
res.send(200, jsonResponse);
|
||||
} else {
|
||||
//status code 400, errno 103: incorrect password
|
||||
jsonResponse = getError(103,accountSelected);
|
||||
res.send(jsonResponse);
|
||||
}
|
||||
} else {
|
||||
//status code 400, errno 102: attempt to access a non-existent account
|
||||
jsonResponse = getError(102, accountSelected);
|
||||
res.send(jsonResponse);
|
||||
}
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
}
|
||||
|
||||
/************************************
|
||||
* API: Recovery Email
|
||||
************************************/
|
||||
|
||||
function getRecoveryEmailStatus(req,res,next) {
|
||||
var accountSelected = getAccountType(req.body.email);
|
||||
var jsonResponse = getRespRecoveryEmail(accountSelected);
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
/************************************
|
||||
* API: Certificate Signing
|
||||
************************************/
|
||||
|
||||
function postCertificateSign(req,res,next) {
|
||||
var jsonResponse = {
|
||||
'cert': randomString(520,
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZ.abcdefghijklmnopqrstuvwxyz0123456789')
|
||||
};
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
/************************************
|
||||
* API: Password
|
||||
************************************/
|
||||
|
||||
/**
|
||||
* should verify request of format:
|
||||
* {
|
||||
* "email": "me@example.com",
|
||||
* "oldAuthPW":
|
||||
* "d486e79c9f3214b0010fe31bfb50fa6c12e1d093f7770c81c6b1c19c7ee375a6"
|
||||
* }
|
||||
*/
|
||||
function postPasswordChangeStart(req,res,next) {
|
||||
|
||||
var accountSelected = getAccountType(req.body.email);
|
||||
var jsonResponse;
|
||||
if (req.body.email === account.exists.email) {
|
||||
jsonResponse = getRespPasswordChangeStart(accountSelected);
|
||||
res.send(200, jsonResponse);
|
||||
} else {
|
||||
//status code 400, errno 102: attempt to access non-existent account
|
||||
jsonResponse = getError(102, accountSelected);
|
||||
res.send(jsonResponse);
|
||||
}
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
function postPasswordForgotSendCode(req,res,next) {
|
||||
var jsonResponse = getRespPasswordForgotSendCode();
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
function postPasswordForgotResendCode(req,res,next) {
|
||||
var jsonResponse = getRespPasswordForgotSendCode();
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
function postPasswordForgotVerifyCode(req,res,next) {
|
||||
var jsonResponse = {
|
||||
'accountResetToken': randomString(128)
|
||||
};
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
function getPasswordForgotStatus(req,res,next) {
|
||||
var jsonResponse = { 'tries': 3, 'ttl': 420 };
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
/************************************
|
||||
* API: Miscellaneous
|
||||
************************************/
|
||||
|
||||
function postGetRandomBytes(req,res,next) {
|
||||
var randomData = getRandomBytes();
|
||||
var jsonResponse = { 'data': randomData };
|
||||
printLog(req.method + ' ' + req.url, jsonResponse);
|
||||
res.send(200,jsonResponse);
|
||||
}
|
||||
|
||||
/************************************
|
||||
* API: Undefined
|
||||
* any other requests land here
|
||||
************************************/
|
||||
|
||||
function anyUndefined(req,res,next) {
|
||||
printLog(req.method + ' ' + req.url + ' (UNDEFINED)',
|
||||
'value of req is: ' + req);
|
||||
}
|
||||
|
||||
function randomString(len, charSet) {
|
||||
charSet = charSet || 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
var rand = '';
|
||||
for (var i = 0; i < len; i++) {
|
||||
var randomPoz = Math.floor(Math.random() * charSet.length);
|
||||
rand += charSet.substring(randomPoz,randomPoz+1);
|
||||
}
|
||||
return rand;
|
||||
}
|
||||
|
||||
/**
|
||||
* mock API will random 64 char length hex strings
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRandomBytes() {
|
||||
return randomString(64);
|
||||
}
|
||||
|
||||
function getAccountType(returnType) {
|
||||
switch(returnType) {
|
||||
case account.exists.email:
|
||||
return account.exists;
|
||||
default:
|
||||
return account.new;
|
||||
}
|
||||
}
|
||||
|
||||
function respondEmpty(req,res,next) {
|
||||
printLog(req.method + ' ' + req.url, {});
|
||||
res.send(200, {});
|
||||
}
|
||||
|
||||
function getRespAccountLogin(accountSelected) {
|
||||
return {
|
||||
'uid': accountSelected.uid,
|
||||
'sessionToken': accountSelected.sessionToken,
|
||||
'verified': accountSelected.verified,
|
||||
'authAt': Date.now()
|
||||
};
|
||||
}
|
||||
|
||||
function getRespRecoveryEmail(accountSelected) {
|
||||
return {
|
||||
'email': accountSelected.email,
|
||||
'verified': accountSelected.verified
|
||||
};
|
||||
}
|
||||
|
||||
function getRespAccountCreate(accountSelected) {
|
||||
return {
|
||||
'uid': accountSelected.uid,
|
||||
'sessionToken': accountSelected.sessionToken,
|
||||
'keyFetchToken': accountSelected.keyFetchToken,
|
||||
'authAt': Date.now()
|
||||
};
|
||||
}
|
||||
|
||||
function getRespPasswordChangeStart(accountSelected) {
|
||||
return {
|
||||
'keyFetchToken': accountSelected.keyFetchToken,
|
||||
'passwordChangeToken': accountSelected.passwordChangeToken,
|
||||
'verified': accountSelected.verified
|
||||
};
|
||||
}
|
||||
|
||||
function getRespPasswordForgotSendCode() {
|
||||
return {
|
||||
'passwordForgotToken': randomString(128),
|
||||
'ttl': 900,
|
||||
'codeLength': 8,
|
||||
'tries': 3
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Use:
|
||||
* var errNum = req.socket._httpMessage.statusCode;
|
||||
* @param errNum
|
||||
* @param accountSelected
|
||||
* @returns {*}
|
||||
*/
|
||||
function getError(errNum,accountSelected) {
|
||||
var info = config.AUTH_SERVER_URL;
|
||||
switch(errNum) {
|
||||
case 102:
|
||||
return {
|
||||
'code': 400,
|
||||
'errno': errNum,
|
||||
'error': 'Bad Request',
|
||||
'message': 'Attempt to access an account that does not exist',
|
||||
'info': info,
|
||||
'email': accountSelected.email,
|
||||
'log': []
|
||||
};
|
||||
|
||||
case 103:
|
||||
return {
|
||||
'code': 400,
|
||||
'errno': errNum,
|
||||
'error': 'Bad Request',
|
||||
'message': 'Incorrect password',
|
||||
'info': info,
|
||||
'email': accountSelected.email,
|
||||
'log': []
|
||||
};
|
||||
|
||||
case 999:
|
||||
return {
|
||||
'code': errNum,
|
||||
'errno': 999,
|
||||
'error': 'Not Found',
|
||||
'message': 'Unspecified error',
|
||||
'info': info,
|
||||
'log': []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log req/res to stdout
|
||||
*/
|
||||
function printLog(title,msg) {
|
||||
if (config.DEBUG) {
|
||||
console.log('\n========================');
|
||||
console.log(title);
|
||||
console.log('========================');
|
||||
console.log(msg);
|
||||
console.log('\n\n');
|
||||
}
|
||||
}
|
||||
37
gaia/tv_apps/smart-system/fxa/test/marionette/test-fxa-client/index.html
Executable file
37
gaia/tv_apps/smart-system/fxa/test/marionette/test-fxa-client/index.html
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>FxAccounts testing tools</title>
|
||||
<!-- We don't need localization for this app. -->
|
||||
<script defer type="text/javascript" src="/js/fxa_iac_client.js"></script>
|
||||
<script defer type="text/javascript" src="/js/app.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="style/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<section role="dialog">
|
||||
<menu>
|
||||
<button id="getAccount">Get Fx Account</button>
|
||||
<button id="openFlow">Launch FxAccounts flow</button>
|
||||
<button id="logout">Logout</button>
|
||||
<div class="refresh-auth">
|
||||
<button id="refreshAuthentication">Refresh Authentication UI</button>
|
||||
<input id="accountId" type="text" value="dummy@account" x-inputmode="verbatim">
|
||||
</div>
|
||||
</menu>
|
||||
|
||||
<section id="result">
|
||||
<p id="result-text"></p>
|
||||
</section>
|
||||
|
||||
<section id="events">
|
||||
<p id="events-text"></p>
|
||||
</section>
|
||||
</section>
|
||||
<!-- Progress overlay -->
|
||||
<section id="overlay" role="dialog">
|
||||
<progress></progress>
|
||||
<p id="overlay-msg">Connecting to Firefox</p>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
124
gaia/tv_apps/smart-system/fxa/test/marionette/test-fxa-client/js/app.js
Executable file
124
gaia/tv_apps/smart-system/fxa/test/marionette/test-fxa-client/js/app.js
Executable file
|
|
@ -0,0 +1,124 @@
|
|||
'use strict';
|
||||
/* global FxAccountsIACHelper */
|
||||
|
||||
var hideTimer;
|
||||
var Overlay = {
|
||||
show: function fxam_overlay_show() {
|
||||
if (hideTimer) {
|
||||
return;
|
||||
}
|
||||
var overlay = document.querySelector('#overlay');
|
||||
overlay.classList.add('show');
|
||||
hideTimer = setTimeout(Overlay.hide, 2000);
|
||||
},
|
||||
hide: function fxam_overlay_hide() {
|
||||
hideTimer = clearTimeout(hideTimer);
|
||||
var overlay = document.querySelector('#overlay');
|
||||
if (!overlay) {
|
||||
return;
|
||||
}
|
||||
overlay.classList.remove('show');
|
||||
}
|
||||
};
|
||||
|
||||
var TestFxAClient = function TestFxAClient() {
|
||||
|
||||
var getFxAccountsButton, launchFxAFlowButton, logoutButton,
|
||||
refreshAuthButton, resultTextEl, resultEl, timer, eventsEl,
|
||||
eventsTextEl, eventsTimer, accountIdInput;
|
||||
|
||||
var init = function init() {
|
||||
resultEl = document.getElementById('result');
|
||||
resultTextEl = document.getElementById('result-text');
|
||||
getFxAccountsButton = document.getElementById('getAccount');
|
||||
launchFxAFlowButton = document.getElementById('openFlow');
|
||||
logoutButton = document.getElementById('logout');
|
||||
refreshAuthButton = document.getElementById('refreshAuthentication');
|
||||
eventsEl = document.getElementById('events');
|
||||
eventsTextEl = document.getElementById('events-text');
|
||||
accountIdInput = document.getElementById('accountId');
|
||||
|
||||
getFxAccountsButton.addEventListener('click', handler);
|
||||
launchFxAFlowButton.addEventListener('click', handler);
|
||||
logoutButton.addEventListener('click', handler);
|
||||
refreshAuthButton.addEventListener('click', handler);
|
||||
|
||||
FxAccountsIACHelper.addEventListener('onlogin', function() {
|
||||
showEvent('onlogin');
|
||||
});
|
||||
|
||||
FxAccountsIACHelper.addEventListener('onlogout', function() {
|
||||
showEvent('onlogout');
|
||||
});
|
||||
|
||||
FxAccountsIACHelper.addEventListener('onverifiedlogin', function() {
|
||||
showEvent('onverifiedlogin');
|
||||
});
|
||||
};
|
||||
|
||||
function _setResponse(response, errorDebug) {
|
||||
resultTextEl.innerHTML = '';
|
||||
|
||||
var text = document.createTextNode((errorDebug)? 'Error ' : 'Success :');
|
||||
resultTextEl.appendChild(text);
|
||||
var responseBeautyfied =
|
||||
document.createTextNode(JSON.stringify(response || 'No params', null, 4));
|
||||
resultTextEl.appendChild(responseBeautyfied);
|
||||
|
||||
clearTimeout(timer);
|
||||
resultEl.classList.add('show');
|
||||
timer = setTimeout(function() {
|
||||
resultEl.classList.remove('show');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function showEvent(eventName) {
|
||||
eventsTextEl.innerHTML = '';
|
||||
|
||||
var text = document.createTextNode('Event received: ' + eventName);
|
||||
eventsTextEl.appendChild(text);
|
||||
|
||||
clearTimeout(timer);
|
||||
eventsEl.classList.add('show');
|
||||
eventsTimer = setTimeout(function() {
|
||||
eventsEl.classList.remove('show');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
var showResponse = function showResponse(response) {
|
||||
Overlay.hide();
|
||||
_setResponse(response);
|
||||
};
|
||||
|
||||
var showError = function showResponse(response) {
|
||||
Overlay.hide();
|
||||
_setResponse(response, true);
|
||||
};
|
||||
|
||||
var handler = function handler(evt) {
|
||||
var method = evt.target.id;
|
||||
switch (method) {
|
||||
case 'openFlow':
|
||||
FxAccountsIACHelper[method](showResponse, showError);
|
||||
break;
|
||||
case 'getAccount':
|
||||
case 'logout':
|
||||
Overlay.show();
|
||||
FxAccountsIACHelper[method](showResponse, showError);
|
||||
break;
|
||||
case 'refreshAuthentication':
|
||||
FxAccountsIACHelper[method](accountIdInput.value,
|
||||
showResponse, showError);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
'init': init
|
||||
};
|
||||
|
||||
}();
|
||||
|
||||
TestFxAClient.init();
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "Test FxA Client",
|
||||
"launch_path": "/index.html",
|
||||
"type": "certified",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"icons": {
|
||||
"120": "/style/icons/icon.png"
|
||||
},
|
||||
"orientation": "default"
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -0,0 +1,97 @@
|
|||
html, body {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
/* XXX: The below overflow property is being ignored by B2G Phone
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=777672
|
||||
*/
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 6rem;
|
||||
line-height: 6rem;
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
menu {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#result {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#result.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#events {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#events.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding: 1rem 1.5rem;
|
||||
-moz-box-sizing: border-box;
|
||||
font-size: 2rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
p {
|
||||
padding: 1rem 1.5rem;
|
||||
-moz-box-sizing: border-box;
|
||||
font-size: 1.6rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Overlay:
|
||||
* IMPORTANT: Avoid to use 'visibility' or 'opacity' due
|
||||
* to performance issues. For hiding, use 'display:none;''
|
||||
* * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#overlay {
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
font-size: 2rem;
|
||||
background-color: rgba(200,200,200,0.9);
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#overlay.show {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
height: 4rem;
|
||||
line-height: 6rem;
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.refresh-auth {
|
||||
border-top: 0.1rem solid;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
Loading…
Reference in a new issue