-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GPII-3496: Auto-login with user folder #839
base: master
Are you sure you want to change the base?
Changes from all commits
1277344
807b7f6
6256052
0d1bb73
915ed3b
db69e07
79129f2
407d299
20315bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,10 +18,14 @@ | |
|
||
"use strict"; | ||
|
||
var fluid = require("infusion"); | ||
var fluid = require("infusion"), | ||
fs = require("fs"), | ||
path = require("path"); | ||
|
||
var gpii = fluid.registerNamespace("gpii"); | ||
|
||
require("../../lifecycleManager/"); | ||
|
||
fluid.registerNamespace("gpii.userListeners"); | ||
|
||
// The user listeners. | ||
|
@@ -55,6 +59,15 @@ fluid.defaults("gpii.userListeners", { | |
onListenersStop: "{userListeners}.events.onListenersStop" | ||
} | ||
} | ||
}, | ||
userFolder: { | ||
type: "gpii.userListeners.userFolder", | ||
options: { | ||
events: { | ||
onListenersStart: "{userListeners}.events.onListenersStart", | ||
onListenersStop: "{userListeners}.events.onListenersStop" | ||
} | ||
} | ||
} | ||
}, | ||
events: { | ||
|
@@ -106,6 +119,14 @@ fluid.defaults("gpii.userListener", { | |
"{that}", | ||
"{arguments}.0" // The error. | ||
] | ||
}, | ||
readTokenFile: { | ||
funcName: "gpii.userListeners.readTokenFile", | ||
args: [ "{arguments}.0", "{arguments}.1" ] // directory, file | ||
}, | ||
writeTokenFile: { | ||
funcName: "gpii.userListeners.writeTokenFile", | ||
args: [ "{arguments}.0", "{arguments}.1", "{arguments}.2" ] // directory, file, token | ||
} | ||
}, | ||
members: { | ||
|
@@ -208,3 +229,78 @@ gpii.userListeners.failed = function (that, err) { | |
}); | ||
}); | ||
}; | ||
|
||
/** | ||
* Reads a token from the file. | ||
* | ||
* @param {String} tokenDirectory - The directory containing the token file. | ||
* @param {String} tokenFile [optional] The file, in tokenDirectory, containing the token. Can be omitted if the first | ||
* argument is the full path to the file. | ||
* @return {Promise} resolves when the token is read, rejects if there's no file (or there was an error reading it). | ||
*/ | ||
gpii.userListeners.readTokenFile = function (tokenDirectory, tokenFile) { | ||
var promise = fluid.promise(); | ||
|
||
// Try to read the token file. | ||
var tokenPath = path.join(tokenDirectory, tokenFile || ""); | ||
fluid.log("Reading token file: ", tokenPath); | ||
fs.readFile(tokenPath, "utf8", function (err, data) { | ||
if (err) { | ||
if (err.code === "ENOENT") { | ||
fluid.log("Token file not found"); | ||
promise.reject(); | ||
} else { | ||
var message = "Error reading token file " + tokenPath + ": " + err.message; | ||
fluid.log(message); | ||
promise.reject({ | ||
isError: true, | ||
message: message, | ||
error: err | ||
}); | ||
} | ||
} else { | ||
var token = data.trim(); | ||
if (token.length > 0) { | ||
fluid.log("Got token: ", token); | ||
promise.resolve(token); | ||
} else { | ||
fluid.log("Empty token file"); | ||
promise.reject(); | ||
} | ||
} | ||
}); | ||
|
||
return promise; | ||
}; | ||
|
||
/** | ||
* Writes a token to a file. | ||
* | ||
* @param {String} tokenDirectory - The directory containing the token file. | ||
* @param {String} tokenFile [optional] The file, in tokenDirectory, containing the token. Can be omitted if the first | ||
* argument is the full path to the file. | ||
* @param {String} tokenValue - The token's value. | ||
* @return {Promise} resolves when complete, with a value of true if it was written. | ||
*/ | ||
gpii.userListeners.writeTokenFile = function (tokenDirectory, tokenFile, tokenValue) { | ||
var promise = fluid.promise(); | ||
|
||
var tokenPath = path.join(tokenDirectory, tokenFile || ""); | ||
fluid.log("Writing token '" + tokenValue + "' to ", tokenPath); | ||
|
||
fs.writeFile(tokenPath, tokenValue, "utf8", function (err) { | ||
if (err) { | ||
var message = "Error writing token file " + tokenPath + ": " + err.message; | ||
fluid.log(message); | ||
promise.reject({ | ||
isError: true, | ||
message: message, | ||
error: err | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to the convention, the path for the original error object is named as "originalError" rather than "error". |
||
}); | ||
} else { | ||
promise.resolve(true); | ||
} | ||
}); | ||
|
||
return promise; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* userFolder user listener. | ||
* | ||
* Copyright 2017 Raising the Floor - International | ||
* | ||
* Licensed under the New BSD license. You may not use this file except in | ||
* compliance with this License. | ||
* | ||
* The R&D leading to these results received funding from the | ||
* Department of Education - Grant H421A150005 (GPII-APCP). However, | ||
* these results do not necessarily represent the policy of the | ||
* Department of Education, and you should not assume endorsement by the | ||
* Federal Government. | ||
* | ||
* You may obtain a copy of the License at | ||
* https://github.com/GPII/universal/blob/master/LICENSE.txt | ||
*/ | ||
|
||
"use strict"; | ||
|
||
var fluid = require("infusion"); | ||
|
||
var gpii = fluid.registerNamespace("gpii"); | ||
|
||
// The user folder user listener. | ||
fluid.defaults("gpii.userListeners.userFolder", { | ||
gradeNames: ["fluid.component", "fluid.contextAware", "gpii.userListener"], | ||
contextAwareness: { | ||
platform: { | ||
checks: { | ||
windows: { | ||
contextValue: "{gpii.contexts.windows}", | ||
gradeNames: "gpii.userListeners.userFolder.windows" | ||
} | ||
} | ||
} | ||
}, | ||
members: { | ||
tokenDirectory: "@expand:{settingsDir}.getGpiiSettingsDir()", | ||
tokenFile: ".gpii-user-token.txt", | ||
done: false, | ||
listenerName: "userFolder" | ||
}, | ||
components: { | ||
settingsDir: { | ||
type: "gpii.settingsDir" | ||
} | ||
}, | ||
invokers: { | ||
startListener: "{that}.attemptLogin", | ||
stopListener: "fluid.identity", | ||
attemptLogin: { | ||
funcName: "gpii.userListeners.userFolder.attemptLogin", | ||
args: ["{that}"] | ||
}, | ||
getToken: { | ||
func: "{that}.readTokenFile", | ||
args: ["{that}.tokenDirectory", "{that}.tokenFile"] | ||
}, | ||
storeToken: { | ||
func: "{that}.writeTokenFile", | ||
args: [ "{that}.tokenDirectory", "{that}.tokenFile", "{arguments}.0" ] | ||
} | ||
}, | ||
listeners: { | ||
"onCreate.loginListener": { | ||
funcName: "gpii.userListeners.userFolder.addLoginListener", | ||
args: [ "{that}", "{lifecycleManager}.events.onSessionStart"] | ||
} | ||
}, | ||
// Disabling by default, as it is the safest and will prevent people's keys from being accidentally stored when it | ||
// is not desired (eg, on shared or public access computers). | ||
saveLastLogin: false | ||
}); | ||
|
||
/** | ||
* Adds a listener to the onSessionStart event of the lifecycle manager, which stores the token file. | ||
* | ||
* @param {Component} that The gpii.userListeners.userFolder instance. | ||
* @param {EventFirer} firer The event firer for the onSessionStart event. | ||
*/ | ||
gpii.userListeners.userFolder.addLoginListener = function (that, firer) { | ||
if (that.options.saveLastLogin) { | ||
firer.addListener(function (gradeName, gpiiKey) { | ||
if (gpiiKey !== "noUser") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might like to check the gpiiKey is not any of reserved keys. A list of reserved keys can be found [here|https://github.com/GPII/universal/blob/master/gpii/node_modules/flowManager/src/SystemUtils.js#L19|. |
||
that.storeToken(gpiiKey); | ||
} | ||
}); | ||
} | ||
}; | ||
|
||
/** | ||
* Performs the key-in, by raising the onTokenArrive event with the result of getToken(). | ||
* | ||
* This should only be called once, during startup. Subsequent calls will have no effect. | ||
* | ||
* @param {Component} that - The gpii.userListeners.userFolder instance. | ||
* @return {Promise} A promise resolving when the token has been read. | ||
*/ | ||
gpii.userListeners.userFolder.attemptLogin = function (that) { | ||
var promise; | ||
|
||
if (that.done) { | ||
promise = fluid.promise().reject({ | ||
isError: true, | ||
message: "userFolder.attemptLogin had already been called." | ||
}); | ||
} else { | ||
that.done = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall this line be inside the |
||
promise = that.getToken().then(function (token) { | ||
that.events.onTokenArrive.fire(that, token); | ||
}); | ||
} | ||
|
||
return promise; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,3 +20,4 @@ | |
|
||
require("./pcscTests.js"); | ||
require("./usbTests.js"); | ||
require("./userFolderTests.js"); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -134,6 +134,28 @@ fluid.defaults("gpii.test.userListeners.pcsc", { | |
} | ||
}); | ||
|
||
/* | ||
* Get an instance of the gpii.userListeners.pcsc component. | ||
*/ | ||
gpii.tests.userListener.getPcscListener = function () { | ||
var userListeners = gpii.userListeners({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did these new global functions need to get added for each test function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also.... nothing calls this function? |
||
listeners: { | ||
"onCreate.startListeners": "fluid.identity" | ||
}, | ||
events: { | ||
"onListenersStart": null | ||
}, | ||
distributeOptions: { | ||
pcsc: { | ||
record: "gpii.test.userListeners.pcsc", | ||
target: "{that pcsc}.options.gradeNames" | ||
} | ||
} | ||
}); | ||
|
||
return userListeners.pcsc; | ||
}; | ||
|
||
/** | ||
* Creates a card reader that emulates a real reader, by returning a canned response to commands. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please replace the use of "token" with "GPII key". Thanks.