Add reference documentation using sdocs

This commit is contained in:
Ritchie 2013-12-19 17:49:47 -08:00
parent a47317de0d
commit fcc4bba82d
9 changed files with 222 additions and 69 deletions

View File

@ -3,6 +3,14 @@
"content": [
"docs/api.md",
"docs/api-app.md",
"lib/models/access-token.js",
"lib/models/access-context.js",
"lib/models/acl.js",
"lib/models/application.js",
"lib/models/email.js",
"lib/models/model.js",
"lib/models/role.js",
"lib/models/user.js",
"docs/api-datasource.md",
"docs/api-geopoint.md",
"docs/api-model.md",

View File

@ -6,7 +6,7 @@ var debug = require('debug')('loopback:security:access-context');
* Access context represents the context for a request to access protected
* resources
*
* The AccessContext instance contains the following properties:
* @class
* @property {Principal[]} principals An array of principals
* @property {Function} model The model class
* @property {String} modelName The model name
@ -175,7 +175,7 @@ AccessContext.prototype.debug = function() {
* @param {*} id The princiapl id
* @param {String} [name] The principal name
* @returns {Principal}
* @constructor
* @class
*/
function Principal(type, id, name) {
if (!(this instanceof Principal)) {
@ -211,7 +211,7 @@ Principal.prototype.equals = function (p) {
* @param {String} accessType The access type
* @param {String} permission The permission
* @returns {AccessRequest}
* @constructor
* @class
*/
function AccessRequest(model, property, accessType, permission) {
if (!(this instanceof AccessRequest)) {

View File

@ -1,4 +1,4 @@
/**
/*!
* Module Dependencies.
*/
@ -14,6 +14,10 @@ var Model = require('../loopback').Model
/**
* Default AccessToken properties.
*
* @property id {String} - Generated token ID
* @property ttl {Number} - Time to live
* @property created {Date} - When the token was created
*/
var properties = {
@ -25,7 +29,15 @@ var properties = {
};
/**
* Extends from the built in `loopback.Model` type.
* Token based authentication and access control.
*
* **Default ACLs**
*
* - DENY EVERYONE `*`
* - ALLOW EVERYONE create
*
* @class
* @inherits {Model}
*/
var AccessToken = module.exports = Model.extend('AccessToken', properties, {
@ -44,12 +56,22 @@ var AccessToken = module.exports = Model.extend('AccessToken', properties, {
]
});
/**
* Anonymous Token
*
* ```js
* assert(AccessToken.ANONYMOUS.id === '$anonymous');
* ```
*/
AccessToken.ANONYMOUS = new AccessToken({id: '$anonymous'});
/**
* Create a cryptographically random access token id.
*
* @param {Function} callback
* @callback {Function} callback
* @param {Error} err
* @param {String} token
*/
AccessToken.createAccessTokenId = function (fn) {
@ -85,7 +107,9 @@ AccessToken.beforeCreate = function (next, data) {
*
* @param {ServerRequest} req
* @param {Object} [options] Options for finding the token
* @param {Function} callback Calls back with a token if one exists otherwise null or an error.
* @callback {Function} callback
* @param {Error} err
* @param {AccessToken} token
*/
AccessToken.findForRequest = function(req, options, cb) {
@ -116,6 +140,14 @@ AccessToken.findForRequest = function(req, options, cb) {
}
}
/**
* Validate the token.
*
* @callback {Function} callback
* @param {Error} err
* @param {Boolean} isValid
*/
AccessToken.prototype.validate = function(cb) {
try {
assert(

View File

@ -1,4 +1,4 @@
/**
/*!
Schema ACL options
Object level permissions, for example, an album owned by a user
@ -44,7 +44,7 @@ var AccessRequest = ctx.AccessRequest;
var role = require('./role');
var Role = role.Role;
/**
/*!
* Schema for Scope which represents the permissions that are granted to client
* applications by the resource owner
*/
@ -53,7 +53,6 @@ var ScopeSchema = {
description: String
};
/**
* Resource owner grants/delegates permissions to client applications
*
@ -61,10 +60,31 @@ var ScopeSchema = {
* from the resource owner (user or system)?
*
* Scope has many resource access entries
* @type {createModel|*}
* @class
*/
var Scope = loopback.createModel('Scope', ScopeSchema);
/**
* Check if the given scope is allowed to access the model/property
* @param {String} scope The scope name
* @param {String} model The model name
* @param {String} property The property/method/relation name
* @param {String} accessType The access type
* @callback {Function} callback
* @param {String|Error} err The error object
* @param {AccessRequest} result The access permission
*/
Scope.checkPermission = function (scope, model, property, accessType, callback) {
Scope.findOne({where: {name: scope}}, function (err, scope) {
if (err) {
callback && callback(err);
} else {
ACL.checkPermission(ACL.SCOPE, scope.id, model, property, accessType, callback);
}
});
};
/**
* System grants permissions to principals (users/applications, can be grouped
* into roles).
@ -75,7 +95,6 @@ var Scope = loopback.createModel('Scope', ScopeSchema);
* For a given principal, such as client application and/or user, is it allowed
* to access (read/write/execute)
* the protected resource?
*
*/
var ACLSchema = {
model: String, // The name of the model
@ -105,6 +124,14 @@ var ACLSchema = {
principalId: String
};
/**
* A Model for access control meta data.
*
* @header ACL
* @class
* @inherits Model
*/
var ACL = loopback.createModel('ACL', ACLSchema);
ACL.ALL = AccessContext.ALL;
@ -160,7 +187,7 @@ ACL.getMatchingScore = function getMatchingScore(rule, req) {
* Resolve permission from the ACLs
* @param {Object[]) acls The list of ACLs
* @param {Object} req The request
* @returns {Object} The effective ACL
* @returns {AccessRequest} result The effective ACL
*/
ACL.resolvePermission = function resolvePermission(acls, req) {
// Sort by the matching score in descending order
@ -255,7 +282,7 @@ ACL.getStaticACLs = function getStaticACLs(model, property) {
*
* @callback callback
* @param {String|Error} err The error object
* @param {Object} the access permission
* @param {AccessRequest} result The access permission
*/
ACL.checkPermission = function checkPermission(principalType, principalId,
model, property, accessType,
@ -309,28 +336,6 @@ ACL.prototype.debug = function() {
}
}
/**
* Check if the given scope is allowed to access the model/property
* @param {String} scope The scope name
* @param {String} model The model name
* @param {String} property The property/method/relation name
* @param {String} accessType The access type
* @param {Function} callback The callback function
*
* @callback callback
* @param {String|Error} err The error object
* @param {Object} the access permission
*/
Scope.checkPermission = function (scope, model, property, accessType, callback) {
Scope.findOne({where: {name: scope}}, function (err, scope) {
if (err) {
callback && callback(err);
} else {
ACL.checkPermission(ACL.SCOPE, scope.id, model, property, accessType, callback);
}
});
};
/**
* Check if the request has the permission to access
* @param {Object} context
@ -412,9 +417,8 @@ ACL.checkAccess = function (context, callback) {
* @param {String} model The model name
* @param {*} modelId The model id
* @param {String} method The method name
* @param callback The callback function
*
* @callback callback
* @end
* @callback {Function} callback
* @param {String|Error} err The error object
* @param {Boolean} allowed is the request allowed
*/

View File

@ -106,6 +106,12 @@ function generateKey(hmacKey, algorithm, encoding) {
return hmac.digest('base64');
}
/**
* Manage client applications and organize their users.
* @class
* @inherits {Model}
*/
var Application = loopback.createModel('Application', ApplicationSchema);
/*!
@ -150,7 +156,8 @@ Application.register = function (owner, name, options, cb) {
/**
* Reset keys for the application instance
* @param cb
* @callback {Function} callback
* @param {Error} err
*/
Application.prototype.resetKeys = function (cb) {
this.clientKey = generateKey('client');
@ -164,8 +171,9 @@ Application.prototype.resetKeys = function (cb) {
/**
* Reset keys for a given application by the appId
* @param appId
* @param cb
* @param {Any} appId
* @callback {Function} callback
* @param {Error} err
*/
Application.resetKeys = function (appId, cb) {
Application.findById(appId, function (err, app) {
@ -178,10 +186,21 @@ Application.resetKeys = function (appId, cb) {
};
/**
* Authenticate the application id and key.
*
* @param appId
* @param key
* @param cb
* `matched` will be one of
*
* - clientKey
* - javaScriptKey
* - restApiKey
* - windowsKey
* - masterKey
*
* @param {Any} appId
* @param {String} key
* @callback {Function} callback
* @param {Error} err
* @param {String} matched - The matching key
*/
Application.authenticate = function (appId, key, cb) {
Application.findById(appId, function (err, app) {

View File

@ -1,14 +1,10 @@
/**
/*!
* Module Dependencies.
*/
var Model = require('../loopback').Model
, loopback = require('../loopback');
/**
* Default Email properties.
*/
var properties = {
to: {type: String, required: true},
from: {type: String, required: true},
@ -18,7 +14,43 @@ var properties = {
};
/**
* Extends from the built in `loopback.Model` type.
* The Email Model.
*
* **Properties**
*
* - `to` - **{ String }** **required**
* - `from` - **{ String }** **required**
* - `subject` - **{ String }** **required**
* - `text` - **{ String }**
* - `html` - **{ String }**
*
* @class
* @inherits {Model}
*/
var Email = module.exports = Model.extend('Email', properties);
/**
* Send an email with the given `options`.
*
* Example Options:
*
* ```json
* {
* from: "Fred Foo ✔ <foo@blurdybloop.com>", // sender address
* to: "bar@blurdybloop.com, baz@blurdybloop.com", // list of receivers
* subject: "Hello ✔", // Subject line
* text: "Hello world ✔", // plaintext body
* html: "<b>Hello world ✔</b>" // html body
* }
* ```
*
* See https://github.com/andris9/Nodemailer for other supported options.
*
* @param {Object} options
* @param {Function} callback Called after the e-mail is sent or the sending failed
*/
Email.prototype.send = function() {
throw new Error('You must connect the Email Model to a Mail connector');
}

View File

@ -1,4 +1,4 @@
/**
/*!
* Module Dependencies.
*/
var loopback = require('../loopback');
@ -7,7 +7,10 @@ var modeler = new ModelBuilder();
var assert = require('assert');
/**
* Define the built in loopback.Model.
* The built in loopback.Model.
*
* @class
* @param {Object} data
*/
var Model = module.exports = modeler.define('Model');
@ -124,7 +127,7 @@ function getACL() {
* @param {String} method The method name
* @param callback The callback function
*
* @callback callback
* @callback {Function} callback
* @param {String|Error} err The error object
* @param {Boolean} allowed is the request allowed
*/
@ -136,7 +139,7 @@ Model.checkAccess = function(token, modelId, method, callback) {
ACL.checkAccessForToken(token, this.modelName, modelId, methodName, callback);
};
/**
/*!
* Determine the access type for the given `RemoteMethod`.
*
* @api private

View File

@ -26,6 +26,10 @@ var RoleMappingSchema = {
principalId: String // The principal id
};
/**
* Map Roles to
*/
var RoleMapping = loopback.createModel('RoleMapping', RoleMappingSchema, {
relations: {
role: {
@ -43,7 +47,9 @@ RoleMapping.ROLE = 'ROLE';
/**
* Get the application principal
* @param callback
* @callback {Function} callback
* @param {Error} err
* @param {Application} application
*/
RoleMapping.prototype.application = function (callback) {
if (this.principalType === RoleMapping.APPLICATION) {
@ -57,7 +63,9 @@ RoleMapping.prototype.application = function (callback) {
/**
* Get the user principal
* @param callback
* @callback {Function} callback
* @param {Error} err
* @param {User} user
*/
RoleMapping.prototype.user = function (callback) {
if (this.principalType === RoleMapping.USER) {
@ -71,7 +79,9 @@ RoleMapping.prototype.user = function (callback) {
/**
* Get the child role principal
* @param callback
* @callback {Function} callback
* @param {Error} err
* @param {User} childUser
*/
RoleMapping.prototype.childRole = function (callback) {
if (this.principalType === RoleMapping.ROLE) {
@ -84,7 +94,8 @@ RoleMapping.prototype.childRole = function (callback) {
};
/**
* Define the Role model with `hasMany` relation to RoleMapping
* The Role Model
* @class
*/
var Role = loopback.createModel('Role', RoleSchema, {
relations: {
@ -249,7 +260,9 @@ Role.registerResolver(Role.AUTHENTICATED, function(role, context, callback) {
/**
* Check if the user id is authenticated
* @param {Object} context The security context
* @param {Function} callback The callback function
* @callback {Function} callback
* @param {Error} err
* @param {Boolean} isAuthenticated
*/
Role.isAuthenticated = function isAuthenticated(context, callback) {
process.nextTick(function() {
@ -274,7 +287,9 @@ Role.registerResolver(Role.EVERYONE, function (role, context, callback) {
*
* @param {String} role The role name
* @param {Object} context The context object
* @param {Function} callback
* @callback {Function} callback
* @param {Error} err
* @param {Boolean} isInRole
*/
Role.isInRole = function (role, context, callback) {
debug('isInRole(): %s %j', role, context);
@ -355,7 +370,7 @@ Role.isInRole = function (role, context, callback) {
* @param {Object} context The security context
* @param {Function} callback
*
* @callback callback
* @callback {Function} callback
* @param err
* @param {String[]} An array of role ids
*/

View File

@ -44,11 +44,7 @@ var properties = {
status: String,
created: Date,
lastUpdated: Date
}
/**
* Default User options.
*/
};
var options = {
acls: [
@ -98,6 +94,19 @@ var options = {
/**
* Extends from the built in `loopback.Model` type.
*
* Default `User` ACLs.
*
* - DENY EVERYONE `*`
* - ALLOW EVERYONE `create`
* - ALLOW OWNER `removeById`
* - ALLOW EVERYONE `login`
* - ALLOW EVERYONE `logout`
* - ALLOW EVERYONE `findById`
* - ALLOW OWNER `updateAttributes`
*
* @class
* @inherits {Model}
*/
var User = module.exports = Model.extend('User', properties, options);
@ -105,11 +114,16 @@ var User = module.exports = Model.extend('User', properties, options);
/**
* Login a user by with the given `credentials`.
*
* ```js
* User.login({username: 'foo', password: 'bar'}, function (err, token) {
* console.log(token.id);
* });
* ```
*
* @param {Object} credentials
* @callback {Function} callback
* @param {Error} err
* @param {AccessToken} token
*/
User.login = function (credentials, fn) {
@ -150,11 +164,15 @@ User.login = function (credentials, fn) {
/**
* Logout a user with the given accessToken id.
*
* ```js
* User.logout('asd0a9f8dsj9s0s3223mk', function (err) {
* console.log(err || 'Logged out');
* });
* ```
*
* @param {String} accessTokenID
* @callback {Function} callback
* @param {Error} err
*/
User.logout = function (tokenId, fn) {
@ -188,8 +206,9 @@ User.prototype.hasPassword = function (plain, fn) {
}
/**
* Verify a user's identity.
* Verify a user's identity by sending them a confirmation email.
*
* ```js
* var options = {
* type: 'email',
* to: user.email,
@ -198,6 +217,7 @@ User.prototype.hasPassword = function (plain, fn) {
* };
*
* user.verify(options, next);
* ```
*
* @param {Object} options
*/
@ -266,6 +286,16 @@ User.prototype.verify = function (options, fn) {
}
}
/**
* Confirm the user's identity.
*
* @param {Any} userId
* @param {String} token The validation token
* @param {String} redirect URL to redirect the user to once confirmed
* @callback {Function} callback
* @param {Error} err
*/
User.confirm = function (uid, token, redirect, fn) {
this.findById(uid, function (err, user) {
if(err) {
@ -288,6 +318,16 @@ User.confirm = function (uid, token, redirect, fn) {
});
}
/**
* Create a short lived acess token for temporary login. Allows users
* to change passwords if forgotten.
*
* @options {Object} options
* @prop {String} email The user's email address
* @callback {Function} callback
* @param {Error} err
*/
User.resetPassword = function(options, cb) {
var UserModel = this;
var ttl = UserModel.settings.resetPasswordTokenTTL || DEFAULT_RESET_PW_TTL;
@ -323,7 +363,7 @@ User.resetPassword = function(options, cb) {
}
}
/**
/*!
* Setup an extended user model.
*/