Convert Accounts{Common,Client,Server} to ES2015 classes.

Now with proper documentation!

Closes #4930.
This commit is contained in:
Ben Newman
2015-08-17 17:18:37 -04:00
parent e02bf0fb30
commit 62ced17a9d
11 changed files with 1177 additions and 557 deletions

View File

@@ -1,13 +1,27 @@
// This file is automatically generated by JSDoc; regenerate it with scripts/admin/jsdoc/jsdoc.sh
DocsData = {
"Accounts": {
"filepath": "accounts-base/globals_server.js",
"kind": "namespace",
"filepath": "accounts-base/accounts_common.js",
"instancename": "accountsClientOrServer",
"kind": "class",
"lineno": 1,
"locus": "Anywhere",
"longname": "Accounts",
"name": "Accounts",
"options": [],
"params": [
{
"description": "<p>an object with fields:</p>\n<ul>\n<li>connection {Object} Optional DDP connection to reuse.</li>\n<li>ddpUrl {String} Optional URL for creating a new DDP connection.</li>\n</ul>",
"name": "options",
"type": {
"names": [
"Object"
]
}
}
],
"scope": "global",
"summary": "The namespace for all server-side accounts-related methods."
"summary": "Super-constructor for AccountsClient and AccountsServer."
},
"Accounts.changePassword": {
"filepath": "accounts-password/password_client.js",
@@ -173,6 +187,75 @@ DocsData = {
"scope": "static",
"summary": "Request a forgot password email."
},
"Accounts.onEmailVerificationLink": {
"filepath": "accounts-base/url_client.js",
"forceMemberof": true,
"kind": "member",
"lineno": 115,
"locus": "Client",
"longname": "Accounts.onEmailVerificationLink",
"memberof": "Accounts",
"name": ".onEmailVerificationLink",
"params": [
{
"description": "<p>The function to call. It is given two arguments:</p>\n<ol>\n<li><code>token</code>: An email verification token that can be passed to\n<a href=\"#accounts_verifyemail\"><code>Accounts.verifyEmail</code></a>.</li>\n<li><code>done</code>: A function to call when the email verification UI flow is complete.\nThe normal login process is suspended until this function is called, so\nthat the user can be notified that they are verifying their email before\nbeing logged in.</li>\n</ol>",
"name": "callback",
"type": {
"names": [
"function"
]
}
}
],
"scope": "static",
"summary": "Register a function to call when an email verification link is\nclicked in an email sent by\n[`Accounts.sendVerificationEmail`](#accounts_sendverificationemail).\nThis function should be called in top-level code, not inside\n`Meteor.startup()`."
},
"Accounts.onEnrollmentLink": {
"filepath": "accounts-base/url_client.js",
"forceMemberof": true,
"kind": "member",
"lineno": 142,
"locus": "Client",
"longname": "Accounts.onEnrollmentLink",
"memberof": "Accounts",
"name": ".onEnrollmentLink",
"params": [
{
"description": "<p>The function to call. It is given two arguments:</p>\n<ol>\n<li><code>token</code>: A password reset token that can be passed to\n<a href=\"#accounts_resetpassword\"><code>Accounts.resetPassword</code></a> to give the newly\nenrolled account a password.</li>\n<li><code>done</code>: A function to call when the enrollment UI flow is complete.\nThe normal login process is suspended until this function is called, so that\nuser A can be enrolled even if user B was logged in.</li>\n</ol>",
"name": "callback",
"type": {
"names": [
"function"
]
}
}
],
"scope": "static",
"summary": "Register a function to call when an account enrollment link is\nclicked in an email sent by\n[`Accounts.sendEnrollmentEmail`](#accounts_sendenrollmentemail).\nThis function should be called in top-level code, not inside\n`Meteor.startup()`."
},
"Accounts.onResetPasswordLink": {
"filepath": "accounts-base/url_client.js",
"forceMemberof": true,
"kind": "member",
"lineno": 89,
"locus": "Client",
"longname": "Accounts.onResetPasswordLink",
"memberof": "Accounts",
"name": ".onResetPasswordLink",
"params": [
{
"description": "<p>The function to call. It is given two arguments:</p>\n<ol>\n<li><code>token</code>: A password reset token that can be passed to\n<a href=\"#accounts_resetpassword\"><code>Accounts.resetPassword</code></a>.</li>\n<li><code>done</code>: A function to call when the password reset UI flow is complete. The normal\nlogin process is suspended until this function is called, so that the\npassword for user A can be reset even if user B was logged in.</li>\n</ol>",
"name": "callback",
"type": {
"names": [
"function"
]
}
}
],
"scope": "static",
"summary": "Register a function to call when a reset password link is clicked\nin an email sent by\n[`Accounts.sendResetPasswordEmail`](#accounts_sendresetpasswordemail).\nThis function should be called in top-level code, not inside\n`Meteor.startup()`."
},
"Accounts.resetPassword": {
"filepath": "accounts-password/password_client.js",
"kind": "function",
@@ -467,13 +550,60 @@ DocsData = {
"scope": "static",
"summary": "Marks the user's email address as verified. Logs the user in afterwards."
},
"Ap.config": {
"AccountsClient": {
"augments": [
"AccountsCommon"
],
"filepath": "accounts-base/accounts_client.js",
"instancename": "accountsClient",
"kind": "class",
"lineno": 11,
"locus": "Client",
"longname": "AccountsClient",
"name": "AccountsClient",
"options": [
{
"description": "<p>Optional DDP connection to reuse.</p>",
"name": "connection",
"type": {
"names": [
"Object"
]
}
},
{
"description": "<p>Optional URL for creating a new DDP connection.</p>",
"name": "ddpUrl",
"type": {
"names": [
"String"
]
}
}
],
"params": [
{
"description": "<p>an object with fields:</p>",
"name": "options",
"type": {
"names": [
"Object"
]
}
}
],
"scope": "global",
"summary": "Constructor for the `Accounts` object on the client."
},
"AccountsClient#config": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#config",
"kind": "function",
"lineno": 112,
"lineno": 92,
"locus": "Anywhere",
"longname": "Ap.config",
"memberof": "Ap",
"longname": "AccountsClient#config",
"memberof": "AccountsClient",
"name": "config",
"options": [
{
@@ -533,68 +663,36 @@ DocsData = {
}
}
],
"scope": "static",
"scope": "instance",
"summary": "Set global accounts options."
},
"Ap.onCreateUser": {
"filepath": "accounts-base/accounts_server.js",
"AccountsClient#loggingIn": {
"filepath": "accounts-base/accounts_client.js",
"kind": "function",
"lineno": 1174,
"locus": "Server",
"longname": "Ap.onCreateUser",
"memberof": "Ap",
"name": "onCreateUser",
"options": [],
"params": [
{
"description": "<p>Called whenever a new user is created. Return the new user object, or throw an <code>Error</code> to abort the creation.</p>",
"name": "func",
"type": {
"names": [
"function"
]
}
}
],
"scope": "static",
"summary": "Customize new user creation."
},
"Ap.onEmailVerificationLink": {
"filepath": "accounts-base/url_client.js",
"kind": "function",
"lineno": 129,
"lineno": 54,
"locus": "Client",
"longname": "Ap.onEmailVerificationLink",
"memberof": "Ap",
"name": "onEmailVerificationLink",
"longname": "AccountsClient#loggingIn",
"memberof": "AccountsClient",
"name": "loggingIn",
"options": [],
"params": [
{
"description": "<p>The function to call. It is given two arguments:</p>\n<ol>\n<li><code>token</code>: An email verification token that can be passed to\n<a href=\"#accounts_verifyemail\"><code>Accounts.verifyEmail</code></a>.</li>\n<li><code>done</code>: A function to call when the email verification UI flow is complete.\nThe normal login process is suspended until this function is called, so\nthat the user can be notified that they are verifying their email before\nbeing logged in.</li>\n</ol>",
"name": "callback",
"type": {
"names": [
"function"
]
}
}
],
"scope": "static",
"summary": "Register a function to call when an email verification link is\nclicked in an email sent by\n[`Accounts.sendVerificationEmail`](#accounts_sendverificationemail).\nThis function should be called in top-level code, not inside\n`Meteor.startup()`."
"params": [],
"scope": "instance",
"summary": "True if a login method (such as `Meteor.loginWithPassword`, `Meteor.loginWithFacebook`, or `Accounts.createUser`) is currently in progress. A reactive data source."
},
"Ap.onEnrollmentLink": {
"filepath": "accounts-base/url_client.js",
"AccountsClient#logout": {
"filepath": "accounts-base/accounts_client.js",
"kind": "function",
"lineno": 154,
"lineno": 64,
"locus": "Client",
"longname": "Ap.onEnrollmentLink",
"memberof": "Ap",
"name": "onEnrollmentLink",
"longname": "AccountsClient#logout",
"memberof": "AccountsClient",
"name": "logout",
"options": [],
"params": [
{
"description": "<p>The function to call. It is given two arguments:</p>\n<ol>\n<li><code>token</code>: A password reset token that can be passed to\n<a href=\"#accounts_resetpassword\"><code>Accounts.resetPassword</code></a> to give the newly\nenrolled account a password.</li>\n<li><code>done</code>: A function to call when the enrollment UI flow is complete.\nThe normal login process is suspended until this function is called, so that\nuser A can be enrolled even if user B was logged in.</li>\n</ol>",
"description": "<p>Optional callback. Called with no arguments on success, or with a single <code>Error</code> argument on failure.</p>",
"name": "callback",
"optional": true,
"type": {
"names": [
"function"
@@ -602,16 +700,42 @@ DocsData = {
}
}
],
"scope": "static",
"summary": "Register a function to call when an account enrollment link is\nclicked in an email sent by\n[`Accounts.sendEnrollmentEmail`](#accounts_sendenrollmentemail).\nThis function should be called in top-level code, not inside\n`Meteor.startup()`."
"scope": "instance",
"summary": "Log the user out."
},
"Ap.onLogin": {
"AccountsClient#logoutOtherClients": {
"filepath": "accounts-base/accounts_client.js",
"kind": "function",
"lineno": 83,
"locus": "Client",
"longname": "AccountsClient#logoutOtherClients",
"memberof": "AccountsClient",
"name": "logoutOtherClients",
"options": [],
"params": [
{
"description": "<p>Optional callback. Called with no arguments on success, or with a single <code>Error</code> argument on failure.</p>",
"name": "callback",
"optional": true,
"type": {
"names": [
"function"
]
}
}
],
"scope": "instance",
"summary": "Log out other clients logged in as the current user, but does not log out the client that calls this function."
},
"AccountsClient#onLogin": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#onLogin",
"kind": "function",
"lineno": 242,
"lineno": 146,
"locus": "Anywhere",
"longname": "Ap.onLogin",
"memberof": "Ap",
"longname": "AccountsClient#onLogin",
"memberof": "AccountsClient",
"name": "onLogin",
"options": [],
"params": [
@@ -625,16 +749,18 @@ DocsData = {
}
}
],
"scope": "static",
"scope": "instance",
"summary": "Register a callback to be called after a login attempt succeeds."
},
"Ap.onLoginFailure": {
"AccountsClient#onLoginFailure": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#onLoginFailure",
"kind": "function",
"lineno": 251,
"lineno": 155,
"locus": "Anywhere",
"longname": "Ap.onLoginFailure",
"memberof": "Ap",
"longname": "AccountsClient#onLoginFailure",
"memberof": "AccountsClient",
"name": "onLoginFailure",
"options": [],
"params": [
@@ -648,22 +774,122 @@ DocsData = {
}
}
],
"scope": "static",
"scope": "instance",
"summary": "Register a callback to be called after a login attempt fails."
},
"Ap.onResetPasswordLink": {
"filepath": "accounts-base/url_client.js",
"AccountsClient#user": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#user",
"kind": "function",
"lineno": 104,
"locus": "Client",
"longname": "Ap.onResetPasswordLink",
"memberof": "Ap",
"name": "onResetPasswordLink",
"lineno": 52,
"locus": "Anywhere but publish functions",
"longname": "AccountsClient#user",
"memberof": "AccountsClient",
"name": "user",
"options": [],
"params": [],
"scope": "instance",
"summary": "Get the current user record, or `null` if no user is logged in. A reactive data source."
},
"AccountsClient#userId": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#userId",
"kind": "function",
"lineno": 44,
"locus": "Anywhere but publish functions",
"longname": "AccountsClient#userId",
"memberof": "AccountsClient",
"name": "userId",
"options": [],
"overrides": "AccountsCommon#userId",
"params": [],
"scope": "instance",
"summary": "Get the current user id, or `null` if no user is logged in. A reactive data source."
},
"AccountsCommon#config": {
"filepath": "accounts-base/accounts_common.js",
"kind": "function",
"lineno": 92,
"locus": "Anywhere",
"longname": "AccountsCommon#config",
"memberof": "AccountsCommon",
"name": "config",
"options": [
{
"description": "<p>New users with an email address will receive an address verification email.</p>",
"name": "sendVerificationEmail",
"type": {
"names": [
"Boolean"
]
}
},
{
"description": "<p>Calls to <a href=\"#accounts_createuser\"><code>createUser</code></a> from the client will be rejected. In addition, if you are using <a href=\"#accountsui\">accounts-ui</a>, the &quot;Create account&quot; link will not be available.</p>",
"name": "forbidClientAccountCreation",
"type": {
"names": [
"Boolean"
]
}
},
{
"description": "<p>If set to a string, only allows new users if the domain part of their email address matches the string. If set to a function, only allows new users if the function returns true. The function is passed the full email address of the proposed new user. Works with password-based sign-in and external services that expose email addresses (Google, Facebook, GitHub). All existing users still can log in after enabling this option. Example: <code>Accounts.config({ restrictCreationByEmailDomain: 'school.edu' })</code>.</p>",
"name": "restrictCreationByEmailDomain",
"type": {
"names": [
"String",
"function"
]
}
},
{
"description": "<p>The number of days from when a user logs in until their token expires and they are logged out. Defaults to 90. Set to <code>null</code> to disable login expiration.</p>",
"name": "loginExpirationInDays",
"type": {
"names": [
"Number"
]
}
},
{
"description": "<p>When using the <code>oauth-encryption</code> package, the 16 byte key using to encrypt sensitive account credentials in the database, encoded in base64. This option may only be specifed on the server. See packages/oauth-encryption/README.md for details.</p>",
"name": "oauthSecretKey",
"type": {
"names": [
"String"
]
}
}
],
"params": [
{
"name": "options",
"type": {
"names": [
"Object"
]
}
}
],
"scope": "instance",
"summary": "Set global accounts options."
},
"AccountsCommon#onLogin": {
"filepath": "accounts-base/accounts_common.js",
"kind": "function",
"lineno": 146,
"locus": "Anywhere",
"longname": "AccountsCommon#onLogin",
"memberof": "AccountsCommon",
"name": "onLogin",
"options": [],
"params": [
{
"description": "<p>The function to call. It is given two arguments:</p>\n<ol>\n<li><code>token</code>: A password reset token that can be passed to\n<a href=\"#accounts_resetpassword\"><code>Accounts.resetPassword</code></a>.</li>\n<li><code>done</code>: A function to call when the password reset UI flow is complete. The normal\nlogin process is suspended until this function is called, so that the\npassword for user A can be reset even if user B was logged in.</li>\n</ol>",
"name": "callback",
"description": "<p>The callback to be called when login is successful.</p>",
"name": "func",
"type": {
"names": [
"function"
@@ -671,29 +897,266 @@ DocsData = {
}
}
],
"scope": "static",
"summary": "Register a function to call when a reset password link is clicked\nin an email sent by\n[`Accounts.sendResetPasswordEmail`](#accounts_sendresetpasswordemail).\nThis function should be called in top-level code, not inside\n`Meteor.startup()`."
"scope": "instance",
"summary": "Register a callback to be called after a login attempt succeeds."
},
"Ap.userId": {
"AccountsCommon#onLoginFailure": {
"filepath": "accounts-base/accounts_common.js",
"kind": "function",
"lineno": 41,
"lineno": 155,
"locus": "Anywhere",
"longname": "AccountsCommon#onLoginFailure",
"memberof": "AccountsCommon",
"name": "onLoginFailure",
"options": [],
"params": [
{
"description": "<p>The callback to be called after the login has failed.</p>",
"name": "func",
"type": {
"names": [
"function"
]
}
}
],
"scope": "instance",
"summary": "Register a callback to be called after a login attempt fails."
},
"AccountsCommon#user": {
"filepath": "accounts-base/accounts_common.js",
"kind": "function",
"lineno": 52,
"locus": "Anywhere but publish functions",
"longname": "Ap.userId",
"memberof": "Ap",
"longname": "AccountsCommon#user",
"memberof": "AccountsCommon",
"name": "user",
"options": [],
"params": [],
"scope": "instance",
"summary": "Get the current user record, or `null` if no user is logged in. A reactive data source."
},
"AccountsCommon#userId": {
"filepath": "accounts-base/accounts_common.js",
"kind": "function",
"lineno": 44,
"locus": "Anywhere but publish functions",
"longname": "AccountsCommon#userId",
"memberof": "AccountsCommon",
"name": "userId",
"options": [],
"params": [],
"scope": "static",
"scope": "instance",
"summary": "Get the current user id, or `null` if no user is logged in. A reactive data source."
},
"Ap.validateLoginAttempt": {
"AccountsServer": {
"augments": [
"AccountsCommon"
],
"filepath": "accounts-base/accounts_server.js",
"instancename": "accountsServer",
"kind": "class",
"lineno": 11,
"locus": "Server",
"longname": "AccountsServer",
"name": "AccountsServer",
"options": [],
"params": [
{
"description": "<p>A server object such as <code>Meteor.server</code>.</p>",
"name": "server",
"type": {
"names": [
"Object"
]
}
}
],
"scope": "global",
"summary": "Constructor for the `Accounts` namespace on the server."
},
"AccountsServer#config": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#config",
"kind": "function",
"lineno": 92,
"locus": "Anywhere",
"longname": "AccountsServer#config",
"memberof": "AccountsServer",
"name": "config",
"options": [
{
"description": "<p>New users with an email address will receive an address verification email.</p>",
"name": "sendVerificationEmail",
"type": {
"names": [
"Boolean"
]
}
},
{
"description": "<p>Calls to <a href=\"#accounts_createuser\"><code>createUser</code></a> from the client will be rejected. In addition, if you are using <a href=\"#accountsui\">accounts-ui</a>, the &quot;Create account&quot; link will not be available.</p>",
"name": "forbidClientAccountCreation",
"type": {
"names": [
"Boolean"
]
}
},
{
"description": "<p>If set to a string, only allows new users if the domain part of their email address matches the string. If set to a function, only allows new users if the function returns true. The function is passed the full email address of the proposed new user. Works with password-based sign-in and external services that expose email addresses (Google, Facebook, GitHub). All existing users still can log in after enabling this option. Example: <code>Accounts.config({ restrictCreationByEmailDomain: 'school.edu' })</code>.</p>",
"name": "restrictCreationByEmailDomain",
"type": {
"names": [
"String",
"function"
]
}
},
{
"description": "<p>The number of days from when a user logs in until their token expires and they are logged out. Defaults to 90. Set to <code>null</code> to disable login expiration.</p>",
"name": "loginExpirationInDays",
"type": {
"names": [
"Number"
]
}
},
{
"description": "<p>When using the <code>oauth-encryption</code> package, the 16 byte key using to encrypt sensitive account credentials in the database, encoded in base64. This option may only be specifed on the server. See packages/oauth-encryption/README.md for details.</p>",
"name": "oauthSecretKey",
"type": {
"names": [
"String"
]
}
}
],
"params": [
{
"name": "options",
"type": {
"names": [
"Object"
]
}
}
],
"scope": "instance",
"summary": "Set global accounts options."
},
"AccountsServer#onCreateUser": {
"filepath": "accounts-base/accounts_server.js",
"kind": "function",
"lineno": 91,
"lineno": 116,
"locus": "Server",
"longname": "Ap.validateLoginAttempt",
"memberof": "Ap",
"longname": "AccountsServer#onCreateUser",
"memberof": "AccountsServer",
"name": "onCreateUser",
"options": [],
"params": [
{
"description": "<p>Called whenever a new user is created. Return the new user object, or throw an <code>Error</code> to abort the creation.</p>",
"name": "func",
"type": {
"names": [
"function"
]
}
}
],
"scope": "instance",
"summary": "Customize new user creation."
},
"AccountsServer#onLogin": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#onLogin",
"kind": "function",
"lineno": 146,
"locus": "Anywhere",
"longname": "AccountsServer#onLogin",
"memberof": "AccountsServer",
"name": "onLogin",
"options": [],
"params": [
{
"description": "<p>The callback to be called when login is successful.</p>",
"name": "func",
"type": {
"names": [
"function"
]
}
}
],
"scope": "instance",
"summary": "Register a callback to be called after a login attempt succeeds."
},
"AccountsServer#onLoginFailure": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#onLoginFailure",
"kind": "function",
"lineno": 155,
"locus": "Anywhere",
"longname": "AccountsServer#onLoginFailure",
"memberof": "AccountsServer",
"name": "onLoginFailure",
"options": [],
"params": [
{
"description": "<p>The callback to be called after the login has failed.</p>",
"name": "func",
"type": {
"names": [
"function"
]
}
}
],
"scope": "instance",
"summary": "Register a callback to be called after a login attempt fails."
},
"AccountsServer#user": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#user",
"kind": "function",
"lineno": 52,
"locus": "Anywhere but publish functions",
"longname": "AccountsServer#user",
"memberof": "AccountsServer",
"name": "user",
"options": [],
"params": [],
"scope": "instance",
"summary": "Get the current user record, or `null` if no user is logged in. A reactive data source."
},
"AccountsServer#userId": {
"filepath": "accounts-base/accounts_common.js",
"inherited": true,
"inherits": "AccountsCommon#userId",
"kind": "function",
"lineno": 44,
"locus": "Anywhere but publish functions",
"longname": "AccountsServer#userId",
"memberof": "AccountsServer",
"name": "userId",
"options": [],
"overrides": "AccountsCommon#userId",
"params": [],
"scope": "instance",
"summary": "Get the current user id, or `null` if no user is logged in. A reactive data source."
},
"AccountsServer#validateLoginAttempt": {
"filepath": "accounts-base/accounts_server.js",
"kind": "function",
"lineno": 93,
"locus": "Server",
"longname": "AccountsServer#validateLoginAttempt",
"memberof": "AccountsServer",
"name": "validateLoginAttempt",
"options": [],
"params": [
@@ -707,16 +1170,16 @@ DocsData = {
}
}
],
"scope": "static",
"scope": "instance",
"summary": "Validate login attempts."
},
"Ap.validateNewUser": {
"AccountsServer#validateNewUser": {
"filepath": "accounts-base/accounts_server.js",
"kind": "function",
"lineno": 1257,
"lineno": 103,
"locus": "Server",
"longname": "Ap.validateNewUser",
"memberof": "Ap",
"longname": "AccountsServer#validateNewUser",
"memberof": "AccountsServer",
"name": "validateNewUser",
"options": [],
"params": [
@@ -730,7 +1193,7 @@ DocsData = {
}
}
],
"scope": "static",
"scope": "instance",
"summary": "Set restrictions on new user creation."
},
"App": {
@@ -4113,7 +4576,7 @@ DocsData = {
"Meteor.loggingIn": {
"filepath": "accounts-base/accounts_client.js",
"kind": "function",
"lineno": 53,
"lineno": 134,
"locus": "Client",
"longname": "Meteor.loggingIn",
"memberof": "Meteor",
@@ -4257,7 +4720,7 @@ DocsData = {
"Meteor.logout": {
"filepath": "accounts-base/accounts_client.js",
"kind": "function",
"lineno": 256,
"lineno": 332,
"locus": "Client",
"longname": "Meteor.logout",
"memberof": "Meteor",
@@ -4281,7 +4744,7 @@ DocsData = {
"Meteor.logoutOtherClients": {
"filepath": "accounts-base/accounts_client.js",
"kind": "function",
"lineno": 279,
"lineno": 341,
"locus": "Client",
"longname": "Meteor.logoutOtherClients",
"memberof": "Meteor",
@@ -4305,7 +4768,7 @@ DocsData = {
"Meteor.methods": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1513,
"lineno": 1530,
"locus": "Anywhere",
"longname": "Meteor.methods",
"memberof": "Meteor",
@@ -4328,7 +4791,7 @@ DocsData = {
"Meteor.onConnection": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1374,
"lineno": 1391,
"locus": "Server",
"longname": "Meteor.onConnection",
"memberof": "Meteor",
@@ -4351,7 +4814,7 @@ DocsData = {
"Meteor.publish": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1448,
"lineno": 1465,
"locus": "Server",
"longname": "Meteor.publish",
"memberof": "Meteor",
@@ -4572,7 +5035,7 @@ DocsData = {
"Meteor.user": {
"filepath": "accounts-base/accounts_common.js",
"kind": "function",
"lineno": 61,
"lineno": 229,
"locus": "Anywhere but publish functions",
"longname": "Meteor.user",
"memberof": "Meteor",
@@ -4582,6 +5045,19 @@ DocsData = {
"scope": "static",
"summary": "Get the current user record, or `null` if no user is logged in. A reactive data source."
},
"Meteor.userId": {
"filepath": "accounts-base/accounts_common.js",
"kind": "function",
"lineno": 221,
"locus": "Anywhere but publish functions",
"longname": "Meteor.userId",
"memberof": "Meteor",
"name": "userId",
"options": [],
"params": [],
"scope": "static",
"summary": "Get the current user id, or `null` if no user is logged in. A reactive data source."
},
"Meteor.users": {
"filepath": "accounts-base/globals_server.js",
"kind": "member",
@@ -6233,7 +6709,7 @@ DocsData = {
"filepath": "ddp-server/livedata_server.js",
"instancename": "this",
"kind": "class",
"lineno": 916,
"lineno": 933,
"longname": "Subscription",
"name": "Subscription",
"options": [],
@@ -6244,7 +6720,7 @@ DocsData = {
"Subscription#added": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1204,
"lineno": 1221,
"locus": "Server",
"longname": "Subscription#added",
"memberof": "Subscription",
@@ -6285,7 +6761,7 @@ DocsData = {
"Subscription#changed": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1222,
"lineno": 1239,
"locus": "Server",
"longname": "Subscription#changed",
"memberof": "Subscription",
@@ -6326,7 +6802,7 @@ DocsData = {
"Subscription#connection": {
"filepath": "ddp-server/livedata_server.js",
"kind": "member",
"lineno": 926,
"lineno": 943,
"locus": "Server",
"longname": "Subscription#connection",
"memberof": "Subscription",
@@ -6337,7 +6813,7 @@ DocsData = {
"Subscription#error": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1147,
"lineno": 1164,
"locus": "Server",
"longname": "Subscription#error",
"memberof": "Subscription",
@@ -6360,7 +6836,7 @@ DocsData = {
"Subscription#onStop": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1179,
"lineno": 1196,
"locus": "Server",
"longname": "Subscription#onStop",
"memberof": "Subscription",
@@ -6383,7 +6859,7 @@ DocsData = {
"Subscription#ready": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1255,
"lineno": 1272,
"locus": "Server",
"longname": "Subscription#ready",
"memberof": "Subscription",
@@ -6396,7 +6872,7 @@ DocsData = {
"Subscription#removed": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1238,
"lineno": 1255,
"locus": "Server",
"longname": "Subscription#removed",
"memberof": "Subscription",
@@ -6428,7 +6904,7 @@ DocsData = {
"Subscription#stop": {
"filepath": "ddp-server/livedata_server.js",
"kind": "function",
"lineno": 1165,
"lineno": 1182,
"locus": "Server",
"longname": "Subscription#stop",
"memberof": "Subscription",
@@ -6441,7 +6917,7 @@ DocsData = {
"Subscription#userId": {
"filepath": "ddp-server/livedata_server.js",
"kind": "member",
"lineno": 968,
"lineno": 985,
"locus": "Server",
"longname": "Subscription#userId",
"memberof": "Subscription",
@@ -7186,7 +7662,7 @@ DocsData = {
"filepath": "accounts-base/accounts_client.js",
"ishelper": "true",
"kind": "member",
"lineno": 390,
"lineno": 408,
"longname": "currentUser",
"name": "currentUser",
"scope": "global",
@@ -7214,7 +7690,7 @@ DocsData = {
"filepath": "accounts-base/accounts_client.js",
"ishelper": "true",
"kind": "member",
"lineno": 400,
"lineno": 418,
"longname": "loggingIn",
"name": "loggingIn",
"scope": "global",

View File

@@ -16,7 +16,6 @@ login provider packages: `accounts-password`, `accounts-facebook`,
`accounts-github`, `accounts-google`, `accounts-meetup`,
`accounts-twitter`, or `accounts-weibo`.
{{> autoApiBox "Meteor.user"}}
Retrieves the user record for the current user from
@@ -118,7 +117,6 @@ their user document:
Meteor.users.deny({update: function () { return true; }});
{{> autoApiBox "Meteor.loggingIn"}}
For example, [the `accounts-ui` package](#accountsui) uses this to display an
@@ -239,7 +237,6 @@ the externally-accessible URL, not the URL inside your proxy).
{{> autoApiBox "loggingIn"}}
{{> autoApiBox "Accounts.config"}}
{{> autoApiBox "Accounts.ui.config"}}
Example:
@@ -255,7 +252,64 @@ Example:
passwordSignupFields: 'USERNAME_AND_OPTIONAL_EMAIL'
});
{{> autoApiBox "Accounts.validateNewUser"}}
<h2 id="advanced_accounts_api"><span>Accounts (multi-server)</span></h2>
The `accounts-base` package exports two constructors, called
`AccountsClient` and `AccountsServer`, which are used to create the
`Accounts` object that is available on the client and the server,
respectively.
This predefined `Accounts` object (along with similar convenience methods
of `Meteor`, such as [`Meteor.logout`](#meteor_logout)) is sufficient to
implement most accounts-related logic in Meteor apps. Nevertheless, these
two constructors can be instantiated more than once, to create multiple
independent connections between different accounts servers and their
clients, in more complicated authentication situations.
{{> autoApiBox "AccountsClient" }}
At most one of `options.connection` and `options.ddpUrl` should be
provided in any instantiation of `AccountsClient`. If neither is provided,
`Meteor.connection` will be used as the `.connection` property of the
`AccountsClient` instance.
Note that `AccountsClient` is currently available only on the client, due
to its use of browser APIs such as `window.localStorage`. In principle,
though, it might make sense to establish a client connection from one
server to another remote accounts server. Please [let us
know](https://github.com/meteor/meteor/wiki/Contributing-to-Meteor#feature-requests)
if you find yourself needing this server-to-server functionality.
{{> autoApiBox "AccountsServer" }}
The `AccountsClient` and `AccountsServer` classes share a common
superclass, `AccountsCommon`. Methods defined on
`AccountsCommon.prototype` will be available on both the client and the
server, via the predefined `Accounts` object (most common) or any custom
`accountsClientOrServer` object created using the `AccountsClient` or
`AccountsServer` constructors (less common).
Here are a few of those methods:
{{> autoApiBox "AccountsCommon#userId" }}
{{> autoApiBox "AccountsCommon#user" }}
{{> autoApiBox "AccountsCommon#config"}}
These methods are defined on `AccountsClient.prototype`, and are thus
available only on the client:
{{> autoApiBox "AccountsClient#loggingIn"}}
{{> autoApiBox "AccountsClient#logout"}}
{{> autoApiBox "AccountsClient#logoutOtherClients"}}
These methods are defined on `AccountsServer.prototype`, and are thus
available only on the server:
{{> autoApiBox "AccountsServer#validateNewUser"}}
This can be called multiple times. If any of the functions return `false` or
throw an error, the new user creation is aborted. To set a specific error
@@ -283,7 +337,7 @@ the [`Accounts.validateLoginAttempt`](#accounts_validateloginattempt)
callbacks. If these callbacks succeed but those fail, the user will still be
created but the connection will not be logged in as that user.
{{> autoApiBox "Accounts.onCreateUser"}}
{{> autoApiBox "AccountsServer#onCreateUser"}}
Use this when you need to do more than simply accept or reject new user
creation. With this function you can programatically control the
@@ -321,7 +375,7 @@ Example:
});
{{> autoApiBox "Accounts.validateLoginAttempt"}}
{{> autoApiBox "AccountsServer#validateLoginAttempt"}}
Call `validateLoginAttempt` with a callback to be called on login
attempts. It returns an object with a single method, `stop`. Calling
@@ -387,12 +441,12 @@ to fail, and should start with
return false;
{{> autoApiBox "Accounts.onLogin"}}
{{> autoApiBox "AccountsCommon#onLogin"}}
See description of [Accounts.onLoginFailure](#accounts_onloginfailure)
See description of [AccountsCommon#onLoginFailure](#accounts_onloginfailure)
for details.
{{> autoApiBox "Accounts.onLoginFailure"}}
{{> autoApiBox "AccountsCommon#onLoginFailure"}}
Either the `onLogin` or the `onLoginFailure` callbacks will be called
for each login attempt. The `onLogin` callbacks are called after the

View File

@@ -65,7 +65,7 @@ new password and call `resetPassword`.
{{> autoApiBox "Accounts.resetPassword"}}
This function accepts tokens passed into the callbacks registered with
[`Accounts.onResetPasswordLink`](#Accounts-onResetPasswordLink) and
[`AccountsClient#onResetPasswordLink`](#Accounts-onResetPasswordLink) and
[`Accounts.onEnrollmentLink`](#Accounts-onEnrollmentLink).
{{> autoApiBox "Accounts.setPassword"}}
@@ -78,7 +78,7 @@ This function accepts tokens passed into the callback registered with
{{> autoApiBox "Accounts.sendResetPasswordEmail"}}
When the user visits the link in this email, the callback registered with
[`Accounts.onResetPasswordLink`](#Accounts-onResetPasswordLink) will be called.
[`AccountsClient#onResetPasswordLink`](#Accounts-onResetPasswordLink) will be called.
To customize the contents of the email, see
[`Accounts.emailTemplates`](#accounts_emailtemplates).

View File

@@ -1,6 +1,5 @@
// get the docs id from the name
nameToId = {
"Accounts.onLogin": "accounts_onlogin",
"Meteor.isClient": "meteor_isclient",
"Meteor.isServer": "meteor_isserver",
"Meteor.startup": "meteor_startup",
@@ -41,18 +40,29 @@ nameToId = {
"Session.set": "session_set",
"Subscription#userId": "publish_userId",
"DDPCommon.MethodInvocation#userId": "method_userId",
"AccountsClient": "accountsclient",
"AccountsServer": "accountsserver",
"Accounts.verifyEmail": "accounts_verifyemail",
"Accounts.forgotPassword": "accounts_forgotpassword",
"Accounts.createUser": "accounts_createuser",
"Accounts.validateLoginAttempt": "accounts_validateloginattempt",
"Accounts.onLoginFailure": "accounts_onloginfailure",
"AccountsCommon#userId": "accounts_userid",
"AccountsCommon#user": "accounts_user",
"AccountsCommon#config": "accounts_config",
"AccountsCommon#onLogin": "accounts_onlogin",
"AccountsCommon#onLoginFailure": "accounts_onloginfailure",
"AccountsClient#loggingIn": "accounts_loggingin",
"AccountsServer#validateLoginAttempt": "accounts_validateloginattempt",
"AccountsServer#validateNewUser": "accounts_validatenewuser",
"Accounts.setPassword": "accounts_setpassword",
"Accounts.sendEnrollmentEmail": "accounts_sendenrollmentemail",
"Accounts.onCreateUser": "accounts_oncreateuser",
"AccountsServer#onCreateUser": "accounts_oncreateuser",
"Accounts.sendResetPasswordEmail": "accounts_sendresetpasswordemail",
"Accounts.resetPassword": "accounts_resetpassword",
"Accounts.sendVerificationEmail": "accounts_sendverificationemail",
"Accounts.emailTemplates": "accounts_emailtemplates",
"Accounts.onResetPasswordLink": "Accounts-onResetPasswordLink",
"Accounts.onEnrollmentLink": "Accounts-onEnrollmentLink",
"Accounts.onEmailVerificationLink": "Accounts-onEmailVerificationLink",
"Tracker.flush": "tracker_flush",
"Tracker.afterFlush": "tracker_afterflush",
"Tracker.active": "tracker_active",
@@ -81,11 +91,11 @@ nameToId = {
"DDPCommon.MethodInvocation#connection": "method_connection",
"Mongo.Cursor#count": "count",
"Session.setDefault": "session_set_default",
"AccountsClient#logout": "accounts_logout",
"AccountsClient#logoutOtherClients": "accounts_logoutotherclients",
"Meteor.logout": "meteor_logout",
"Meteor.logoutOtherClients": "meteor_logoutotherclients",
"Meteor.loginWithPassword": "meteor_loginwithpassword",
"Accounts.config": "accounts_config",
"Accounts.validateNewUser": "accounts_validatenewuser",
"Accounts.changePassword": "accounts_changepassword",
"Meteor.setTimeout": "meteor_settimeout",
"Meteor.setInterval": "meteor_setinterval",

View File

@@ -127,13 +127,32 @@ var toc = [
{name: "{{loggingIn}}", id: "template_loggingin"},
{type: "spacer"},
"Accounts.config",
"Accounts.ui.config",
"Accounts.validateNewUser",
"Accounts.onCreateUser",
"Accounts.validateLoginAttempt",
"Accounts.onLogin",
"Accounts.onLoginFailure"
"Accounts.ui.config"
],
{name: "Advanced Accounts", id: "advanced_accounts_api"}, [
"AccountsClient",
"AccountsServer",
{type: "spacer"},
{ name: "AccountsCommon#userId", id: "accounts_userid" },
{ name: "AccountsCommon#user", id: "accounts_user" },
{ name: "AccountsCommon#config", id: "accounts_config" },
{ name: "AccountsCommon#onLogin", id: "accounts_onlogin" },
{ name: "AccountsCommon#onLoginFailure", id: "accounts_onloginfailure" },
{type: "spacer"},
{ name: "AccountsClient#loggingIn", id: "accounts_loggingin" },
{ name: "AccountsClient#logout", id: "accounts_logout" },
{ name: "AccountsClient#logoutOtherClients", id: "accounts_logoutotherclients" },
{type: "spacer"},
{ name: "AccountsServer#onCreateUser",
id: "accounts_oncreateuser" },
{ name: "AccountsServer#validateLoginAttempt",
id: "accounts_validateloginattempt" },
{ name: "AccountsServer#validateNewUser",
id: "accounts_validatenewuser" },
],
{name: "Passwords", id: "accounts_passwords"}, [

View File

@@ -1,10 +1,14 @@
[
"Accounts",
"Accounts",
"Accounts",
"Accounts.changePassword",
"Accounts.createUser",
"Accounts.emailTemplates",
"Accounts.forgotPassword",
"Accounts.onEmailVerificationLink",
"Accounts.onEnrollmentLink",
"Accounts.onResetPasswordLink",
"Accounts.resetPassword",
"Accounts.sendEnrollmentEmail",
"Accounts.sendResetPasswordEmail",
@@ -13,16 +17,29 @@
"Accounts.ui",
"Accounts.ui.config",
"Accounts.verifyEmail",
"Ap.config",
"Ap.onCreateUser",
"Ap.onEmailVerificationLink",
"Ap.onEnrollmentLink",
"Ap.onLogin",
"Ap.onLoginFailure",
"Ap.onResetPasswordLink",
"Ap.userId",
"Ap.validateLoginAttempt",
"Ap.validateNewUser",
"AccountsClient",
"AccountsClient#config",
"AccountsClient#loggingIn",
"AccountsClient#logout",
"AccountsClient#logoutOtherClients",
"AccountsClient#onLogin",
"AccountsClient#onLoginFailure",
"AccountsClient#user",
"AccountsClient#userId",
"AccountsCommon#config",
"AccountsCommon#onLogin",
"AccountsCommon#onLoginFailure",
"AccountsCommon#user",
"AccountsCommon#userId",
"AccountsServer",
"AccountsServer#config",
"AccountsServer#onCreateUser",
"AccountsServer#onLogin",
"AccountsServer#onLoginFailure",
"AccountsServer#user",
"AccountsServer#userId",
"AccountsServer#validateLoginAttempt",
"AccountsServer#validateNewUser",
"App",
"App.accessRule",
"App.configurePlugin",
@@ -160,6 +177,7 @@
"Meteor.status",
"Meteor.subscribe",
"Meteor.user",
"Meteor.userId",
"Meteor.users",
"Meteor.users",
"Meteor.wrapAsync",

View File

@@ -1,51 +1,132 @@
// @summary Constructor for AccountsClient instances. Available only on
// the client for now, though server code might also want to
// create a client connection to an accounts server.
// @locus Client
// @param options {Object} an object with fields:
// - connection {Object} Optional DDP connection to reuse.
// - ddpUrl {String} Optional URL for creating a new DDP connection.
AccountsClient = function _AccountsClient(options) {
AccountsCommon.call(this, options);
/**
* @summary Constructor for the `Accounts` object on the client.
* @locus Client
* @class
* @extends AccountsCommon
* @instancename accountsClient
* @param {Object} options an object with fields:
* @param {Object} options.connection Optional DDP connection to reuse.
* @param {String} options.ddpUrl Optional URL for creating a new DDP connection.
*/
AccountsClient = class AccountsClient extends AccountsCommon {
constructor(options) {
super(options);
this._loggingIn = false;
this._loggingInDeps = new Tracker.Dependency;
this._loggingIn = false;
this._loggingInDeps = new Tracker.Dependency;
this._loginServicesHandle =
this.connection.subscribe("meteor.loginServiceConfiguration");
this._loginServicesHandle =
this.connection.subscribe("meteor.loginServiceConfiguration");
this._pageLoadLoginCallbacks = [];
this._pageLoadLoginAttemptInfo = null;
this._pageLoadLoginCallbacks = [];
this._pageLoadLoginAttemptInfo = null;
// Defined in url_client.js.
this._initUrlMatching();
// Defined in url_client.js.
this._initUrlMatching();
// Defined in localstorage_token.js.
this._initLocalStorage();
};
// Defined in localstorage_token.js.
this._initLocalStorage();
}
Meteor._inherits(AccountsClient, AccountsCommon);
var Ap = AccountsClient.prototype;
///
/// CURRENT USER
///
///
/// CURRENT USER
///
// @override
userId() {
return this.connection.userId();
}
// @override
Ap.userId = function () {
return this.connection.userId();
};
// This is mostly just called within this file, but Meteor.loginWithPassword
// also uses it to make loggingIn() be true during the beginPasswordExchange
// method call too.
_setLoggingIn(x) {
if (this._loggingIn !== x) {
this._loggingIn = x;
this._loggingInDeps.changed();
}
}
// This is mostly just called within this file, but Meteor.loginWithPassword
// also uses it to make loggingIn() be true during the beginPasswordExchange
// method call too.
Ap._setLoggingIn = function (x) {
if (this._loggingIn !== x) {
this._loggingIn = x;
this._loggingInDeps.changed();
/**
* @summary True if a login method (such as `Meteor.loginWithPassword`, `Meteor.loginWithFacebook`, or `Accounts.createUser`) is currently in progress. A reactive data source.
* @locus Client
*/
loggingIn() {
this._loggingInDeps.depend();
return this._loggingIn;
}
/**
* @summary Log the user out.
* @locus Client
* @param {Function} [callback] Optional callback. Called with no arguments on success, or with a single `Error` argument on failure.
*/
logout(callback) {
var self = this;
self.connection.apply('logout', [], {
wait: true
}, function (error, result) {
if (error) {
callback && callback(error);
} else {
self.makeClientLoggedOut();
callback && callback();
}
});
}
/**
* @summary Log out other clients logged in as the current user, but does not log out the client that calls this function.
* @locus Client
* @param {Function} [callback] Optional callback. Called with no arguments on success, or with a single `Error` argument on failure.
*/
logoutOtherClients(callback) {
var self = this;
// We need to make two method calls: one to replace our current token,
// and another to remove all tokens except the current one. We want to
// call these two methods one after the other, without any other
// methods running between them. For example, we don't want `logout`
// to be called in between our two method calls (otherwise the second
// method call would return an error). Another example: we don't want
// logout to be called before the callback for `getNewToken`;
// otherwise we would momentarily log the user out and then write a
// new token to localStorage.
//
// To accomplish this, we make both calls as wait methods, and queue
// them one after the other, without spinning off the event loop in
// between. Even though we queue `removeOtherTokens` before
// `getNewToken`, we won't actually send the `removeOtherTokens` call
// until the `getNewToken` callback has finished running, because they
// are both wait methods.
self.connection.apply(
'getNewToken',
[],
{ wait: true },
function (err, result) {
if (! err) {
self._storeLoginToken(
self.userId(),
result.token,
result.tokenExpires
);
}
}
);
self.connection.apply(
'removeOtherTokens',
[],
{ wait: true },
function (err) {
callback && callback(err);
}
);
}
};
var Ap = AccountsClient.prototype;
/**
* @summary True if a login method (such as `Meteor.loginWithPassword`, `Meteor.loginWithFacebook`, or `Accounts.createUser`) is currently in progress. A reactive data source.
* @locus Client
@@ -54,11 +135,6 @@ Meteor.loggingIn = function () {
return Accounts.loggingIn();
};
Ap.loggingIn = function () {
this._loggingInDeps.depend();
return this._loggingIn;
};
///
/// LOGIN METHODS
///
@@ -257,20 +333,6 @@ Meteor.logout = function (callback) {
return Accounts.logout(callback);
};
Ap.logout = function (callback) {
var self = this;
self.connection.apply('logout', [], {
wait: true
}, function (error, result) {
if (error) {
callback && callback(error);
} else {
self.makeClientLoggedOut();
callback && callback();
}
});
};
/**
* @summary Log out other clients logged in as the current user, but does not log out the client that calls this function.
* @locus Client
@@ -280,50 +342,6 @@ Meteor.logoutOtherClients = function (callback) {
return Accounts.logoutOtherClients(callback);
};
Ap.logoutOtherClients = function (callback) {
var self = this;
// We need to make two method calls: one to replace our current token,
// and another to remove all tokens except the current one. We want to
// call these two methods one after the other, without any other
// methods running between them. For example, we don't want `logout`
// to be called in between our two method calls (otherwise the second
// method call would return an error). Another example: we don't want
// logout to be called before the callback for `getNewToken`;
// otherwise we would momentarily log the user out and then write a
// new token to localStorage.
//
// To accomplish this, we make both calls as wait methods, and queue
// them one after the other, without spinning off the event loop in
// between. Even though we queue `removeOtherTokens` before
// `getNewToken`, we won't actually send the `removeOtherTokens` call
// until the `getNewToken` callback has finished running, because they
// are both wait methods.
self.connection.apply(
'getNewToken',
[],
{ wait: true },
function (err, result) {
if (! err) {
self._storeLoginToken(
self.userId(),
result.token,
result.tokenExpires
);
}
}
);
self.connection.apply(
'removeOtherTokens',
[],
{ wait: true },
function (err) {
callback && callback(err);
}
);
};
///
/// LOGIN SERVICES

View File

@@ -1,55 +1,223 @@
// @summary Super-constructor for AccountsClient an AccountsServer.
// @locus Anywhere
// @param options {Object} an object with fields:
// - connection {Object} Optional DDP connection to reuse.
// - ddpUrl {String} Optional URL for creating a new DDP connection.
AccountsCommon = function _AccountsCommon(options) {
// Currently this is read directly by packages like accounts-password
// and accounts-ui-unstyled.
this._options = {};
/**
* @summary Super-constructor for AccountsClient and AccountsServer.
* @locus Anywhere
* @class Accounts
* @instancename accountsClientOrServer
* @param options {Object} an object with fields:
* - connection {Object} Optional DDP connection to reuse.
* - ddpUrl {String} Optional URL for creating a new DDP connection.
*/
AccountsCommon = class AccountsCommon {
constructor(options) {
// Currently this is read directly by packages like accounts-password
// and accounts-ui-unstyled.
this._options = {};
// Note that setting this.connection = null causes this.users to be a
// LocalCollection, which is not what we want.
this.connection = undefined;
this._initConnection(options || {});
// Note that setting this.connection = null causes this.users to be a
// LocalCollection, which is not what we want.
this.connection = undefined;
this._initConnection(options || {});
// There is an allow call in accounts_server.js that restricts writes to
// this collection.
this.users = new Mongo.Collection("users", {
_preventAutopublish: true,
connection: this.connection
});
// There is an allow call in accounts_server.js that restricts writes to
// this collection.
this.users = new Mongo.Collection("users", {
_preventAutopublish: true,
connection: this.connection
});
// Callback exceptions are printed with Meteor._debug and ignored.
this._onLoginHook = new Hook({
bindEnvironment: false,
debugPrintExceptions: "onLogin callback"
});
// Callback exceptions are printed with Meteor._debug and ignored.
this._onLoginHook = new Hook({
bindEnvironment: false,
debugPrintExceptions: "onLogin callback"
});
this._onLoginFailureHook = new Hook({
bindEnvironment: false,
debugPrintExceptions: "onLoginFailure callback"
});
};
this._onLoginFailureHook = new Hook({
bindEnvironment: false,
debugPrintExceptions: "onLoginFailure callback"
});
}
/**
* @summary Get the current user id, or `null` if no user is logged in. A reactive data source.
* @locus Anywhere but publish functions
*/
userId() {
throw new Error("userId method not implemented");
}
/**
* @summary Get the current user record, or `null` if no user is logged in. A reactive data source.
* @locus Anywhere but publish functions
*/
user() {
var userId = this.userId();
return userId ? this.users.findOne(userId) : null;
}
// Set up config for the accounts system. Call this on both the client
// and the server.
//
// Note that this method gets overridden on AccountsServer.prototype, but
// the overriding method calls the overridden method.
//
// XXX we should add some enforcement that this is called on both the
// client and the server. Otherwise, a user can
// 'forbidClientAccountCreation' only on the client and while it looks
// like their app is secure, the server will still accept createUser
// calls. https://github.com/meteor/meteor/issues/828
//
// @param options {Object} an object with fields:
// - sendVerificationEmail {Boolean}
// Send email address verification emails to new users created from
// client signups.
// - forbidClientAccountCreation {Boolean}
// Do not allow clients to create accounts directly.
// - restrictCreationByEmailDomain {Function or String}
// Require created users to have an email matching the function or
// having the string as domain.
// - loginExpirationInDays {Number}
// Number of days since login until a user is logged out (login token
// expires).
/**
* @summary Set global accounts options.
* @locus Anywhere
* @param {Object} options
* @param {Boolean} options.sendVerificationEmail New users with an email address will receive an address verification email.
* @param {Boolean} options.forbidClientAccountCreation Calls to [`createUser`](#accounts_createuser) from the client will be rejected. In addition, if you are using [accounts-ui](#accountsui), the "Create account" link will not be available.
* @param {String | Function} options.restrictCreationByEmailDomain If set to a string, only allows new users if the domain part of their email address matches the string. If set to a function, only allows new users if the function returns true. The function is passed the full email address of the proposed new user. Works with password-based sign-in and external services that expose email addresses (Google, Facebook, GitHub). All existing users still can log in after enabling this option. Example: `Accounts.config({ restrictCreationByEmailDomain: 'school.edu' })`.
* @param {Number} options.loginExpirationInDays The number of days from when a user logs in until their token expires and they are logged out. Defaults to 90. Set to `null` to disable login expiration.
* @param {String} options.oauthSecretKey When using the `oauth-encryption` package, the 16 byte key using to encrypt sensitive account credentials in the database, encoded in base64. This option may only be specifed on the server. See packages/oauth-encryption/README.md for details.
*/
config(options) {
var self = this;
// We don't want users to accidentally only call Accounts.config on the
// client, where some of the options will have partial effects (eg removing
// the "create account" button from accounts-ui if forbidClientAccountCreation
// is set, or redirecting Google login to a specific-domain page) without
// having their full effects.
if (Meteor.isServer) {
__meteor_runtime_config__.accountsConfigCalled = true;
} else if (!__meteor_runtime_config__.accountsConfigCalled) {
// XXX would be nice to "crash" the client and replace the UI with an error
// message, but there's no trivial way to do this.
Meteor._debug("Accounts.config was called on the client but not on the " +
"server; some configuration options may not take effect.");
}
// We need to validate the oauthSecretKey option at the time
// Accounts.config is called. We also deliberately don't store the
// oauthSecretKey in Accounts._options.
if (_.has(options, "oauthSecretKey")) {
if (Meteor.isClient)
throw new Error("The oauthSecretKey option may only be specified on the server");
if (! Package["oauth-encryption"])
throw new Error("The oauth-encryption package must be loaded to set oauthSecretKey");
Package["oauth-encryption"].OAuthEncryption.loadKey(options.oauthSecretKey);
options = _.omit(options, "oauthSecretKey");
}
// validate option keys
var VALID_KEYS = ["sendVerificationEmail", "forbidClientAccountCreation",
"restrictCreationByEmailDomain", "loginExpirationInDays"];
_.each(_.keys(options), function (key) {
if (!_.contains(VALID_KEYS, key)) {
throw new Error("Accounts.config: Invalid key: " + key);
}
});
// set values in Accounts._options
_.each(VALID_KEYS, function (key) {
if (key in options) {
if (key in self._options) {
throw new Error("Can't set `" + key + "` more than once");
}
self._options[key] = options[key];
}
});
}
/**
* @summary Register a callback to be called after a login attempt succeeds.
* @locus Anywhere
* @param {Function} func The callback to be called when login is successful.
*/
onLogin(func) {
return this._onLoginHook.register(func);
}
/**
* @summary Register a callback to be called after a login attempt fails.
* @locus Anywhere
* @param {Function} func The callback to be called after the login has failed.
*/
onLoginFailure(func) {
return this._onLoginFailureHook.register(func);
}
_initConnection(options) {
if (! Meteor.isClient) {
return;
}
// The connection used by the Accounts system. This is the connection
// that will get logged in by Meteor.login(), and this is the
// connection whose login state will be reflected by Meteor.userId().
//
// It would be much preferable for this to be in accounts_client.js,
// but it has to be here because it's needed to create the
// Meteor.users collection.
if (options.connection) {
this.connection = options.connection;
} else if (options.ddpUrl) {
this.connection = DDP.connect(options.ddpUrl);
} else if (typeof __meteor_runtime_config__ !== "undefined" &&
__meteor_runtime_config__.ACCOUNTS_CONNECTION_URL) {
// Temporary, internal hook to allow the server to point the client
// to a different authentication server. This is for a very
// particular use case that comes up when implementing a oauth
// server. Unsupported and may go away at any point in time.
//
// We will eventually provide a general way to use account-base
// against any DDP connection, not just one special one.
this.connection =
DDP.connect(__meteor_runtime_config__.ACCOUNTS_CONNECTION_URL);
} else {
this.connection = Meteor.connection;
}
}
_getTokenLifetimeMs() {
return (this._options.loginExpirationInDays ||
DEFAULT_LOGIN_EXPIRATION_DAYS) * 24 * 60 * 60 * 1000;
}
_tokenExpiration(when) {
// We pass when through the Date constructor for backwards compatibility;
// `when` used to be a number.
return new Date((new Date(when)).getTime() + this._getTokenLifetimeMs());
}
_tokenExpiresSoon(when) {
var minLifetimeMs = .1 * this._getTokenLifetimeMs();
var minLifetimeCapMs = MIN_TOKEN_LIFETIME_CAP_SECS * 1000;
if (minLifetimeMs > minLifetimeCapMs)
minLifetimeMs = minLifetimeCapMs;
return new Date() > (new Date(when) - minLifetimeMs);
}
}
var Ap = AccountsCommon.prototype;
// Note that Accounts is defined separately in accounts_client.js and
// accounts_server.js.
/**
* @summary Get the current user id, or `null` if no user is logged in. A reactive data source.
* @locus Anywhere but publish functions
*/
Ap.userId = function () {
throw new Error("userId method not implemented");
};
Ap.user = function () {
var userId = this.userId();
return userId ? this.users.findOne(userId) : null;
};
// Note that Accounts is defined separately in accounts_client.js and
// accounts_server.js.
Meteor.userId = function () {
return Accounts.userId();
};
@@ -74,123 +242,6 @@ EXPIRE_TOKENS_INTERVAL_MS = 600 * 1000; // 10 minutes
// called
CONNECTION_CLOSE_DELAY_MS = 10 * 1000;
// Set up config for the accounts system. Call this on both the client
// and the server.
//
// Note that this method gets overridden on AccountsServer.prototype, but
// the overriding method calls the overridden method.
//
// XXX we should add some enforcement that this is called on both the
// client and the server. Otherwise, a user can
// 'forbidClientAccountCreation' only on the client and while it looks
// like their app is secure, the server will still accept createUser
// calls. https://github.com/meteor/meteor/issues/828
//
// @param options {Object} an object with fields:
// - sendVerificationEmail {Boolean}
// Send email address verification emails to new users created from
// client signups.
// - forbidClientAccountCreation {Boolean}
// Do not allow clients to create accounts directly.
// - restrictCreationByEmailDomain {Function or String}
// Require created users to have an email matching the function or
// having the string as domain.
// - loginExpirationInDays {Number}
// Number of days since login until a user is logged out (login token
// expires).
/**
* @summary Set global accounts options.
* @locus Anywhere
* @param {Object} options
* @param {Boolean} options.sendVerificationEmail New users with an email address will receive an address verification email.
* @param {Boolean} options.forbidClientAccountCreation Calls to [`createUser`](#accounts_createuser) from the client will be rejected. In addition, if you are using [accounts-ui](#accountsui), the "Create account" link will not be available.
* @param {String | Function} options.restrictCreationByEmailDomain If set to a string, only allows new users if the domain part of their email address matches the string. If set to a function, only allows new users if the function returns true. The function is passed the full email address of the proposed new user. Works with password-based sign-in and external services that expose email addresses (Google, Facebook, GitHub). All existing users still can log in after enabling this option. Example: `Accounts.config({ restrictCreationByEmailDomain: 'school.edu' })`.
* @param {Number} options.loginExpirationInDays The number of days from when a user logs in until their token expires and they are logged out. Defaults to 90. Set to `null` to disable login expiration.
* @param {String} options.oauthSecretKey When using the `oauth-encryption` package, the 16 byte key using to encrypt sensitive account credentials in the database, encoded in base64. This option may only be specifed on the server. See packages/oauth-encryption/README.md for details.
*/
Ap.config = function (options) {
var self = this;
// We don't want users to accidentally only call Accounts.config on the
// client, where some of the options will have partial effects (eg removing
// the "create account" button from accounts-ui if forbidClientAccountCreation
// is set, or redirecting Google login to a specific-domain page) without
// having their full effects.
if (Meteor.isServer) {
__meteor_runtime_config__.accountsConfigCalled = true;
} else if (!__meteor_runtime_config__.accountsConfigCalled) {
// XXX would be nice to "crash" the client and replace the UI with an error
// message, but there's no trivial way to do this.
Meteor._debug("Accounts.config was called on the client but not on the " +
"server; some configuration options may not take effect.");
}
// We need to validate the oauthSecretKey option at the time
// Accounts.config is called. We also deliberately don't store the
// oauthSecretKey in Accounts._options.
if (_.has(options, "oauthSecretKey")) {
if (Meteor.isClient)
throw new Error("The oauthSecretKey option may only be specified on the server");
if (! Package["oauth-encryption"])
throw new Error("The oauth-encryption package must be loaded to set oauthSecretKey");
Package["oauth-encryption"].OAuthEncryption.loadKey(options.oauthSecretKey);
options = _.omit(options, "oauthSecretKey");
}
// validate option keys
var VALID_KEYS = ["sendVerificationEmail", "forbidClientAccountCreation",
"restrictCreationByEmailDomain", "loginExpirationInDays"];
_.each(_.keys(options), function (key) {
if (!_.contains(VALID_KEYS, key)) {
throw new Error("Accounts.config: Invalid key: " + key);
}
});
// set values in Accounts._options
_.each(VALID_KEYS, function (key) {
if (key in options) {
if (key in self._options) {
throw new Error("Can't set `" + key + "` more than once");
}
self._options[key] = options[key];
}
});
};
Ap._initConnection = function (options) {
if (! Meteor.isClient) {
return;
}
// The connection used by the Accounts system. This is the connection
// that will get logged in by Meteor.login(), and this is the
// connection whose login state will be reflected by Meteor.userId().
//
// It would be much preferable for this to be in accounts_client.js,
// but it has to be here because it's needed to create the
// Meteor.users collection.
if (options.connection) {
this.connection = options.connection;
} else if (options.ddpUrl) {
this.connection = DDP.connect(options.ddpUrl);
} else if (typeof __meteor_runtime_config__ !== "undefined" &&
__meteor_runtime_config__.ACCOUNTS_CONNECTION_URL) {
// Temporary, internal hook to allow the server to point the client
// to a different authentication server. This is for a very
// particular use case that comes up when implementing a oauth
// server. Unsupported and may go away at any point in time.
//
// We will eventually provide a general way to use account-base
// against any DDP connection, not just one special one.
this.connection =
DDP.connect(__meteor_runtime_config__.ACCOUNTS_CONNECTION_URL);
} else {
this.connection = Meteor.connection;
}
};
// loginServiceConfiguration and ConfigError are maintained for backwards compatibility
Meteor.startup(function () {
var ServiceConfiguration =
@@ -214,40 +265,3 @@ Ap.LoginCancelledError.prototype.name = lceName;
// come up with a more generic way to do this (eg, with some sort of symbolic
// error code rather than a number).
Ap.LoginCancelledError.numericError = 0x8acdc2f;
Ap._getTokenLifetimeMs = function () {
return (this._options.loginExpirationInDays ||
DEFAULT_LOGIN_EXPIRATION_DAYS) * 24 * 60 * 60 * 1000;
};
Ap._tokenExpiration = function (when) {
// We pass when through the Date constructor for backwards compatibility;
// `when` used to be a number.
return new Date((new Date(when)).getTime() + this._getTokenLifetimeMs());
};
Ap._tokenExpiresSoon = function (when) {
var minLifetimeMs = .1 * this._getTokenLifetimeMs();
var minLifetimeCapMs = MIN_TOKEN_LIFETIME_CAP_SECS * 1000;
if (minLifetimeMs > minLifetimeCapMs)
minLifetimeMs = minLifetimeCapMs;
return new Date() > (new Date(when) - minLifetimeMs);
};
/**
* @summary Register a callback to be called after a login attempt succeeds.
* @locus Anywhere
* @param {Function} func The callback to be called when login is successful.
*/
Ap.onLogin = function (func) {
return this._onLoginHook.register(func);
};
/**
* @summary Register a callback to be called after a login attempt fails.
* @locus Anywhere
* @param {Function} func The callback to be called after the login has failed.
*/
Ap.onLoginFailure = function (func) {
return this._onLoginFailureHook.register(func);
};

View File

@@ -1,98 +1,129 @@
var crypto = Npm.require('crypto');
// @summary Constructor for the Accounts namespace on the server. Note
// that this constructor is less likely to be instantiated
// multiple times than the AccountsClient constructor, because a
// single server can provide only one set of methods.
// @locus Server
// @param server {Object} Often === Meteor.server; needs to support
// server.methods (like Meteor.methods).
AccountsServer = function AccountsServer(server) {
AccountsCommon.call(this);
this._server = server || Meteor.server;
// Set up the server's methods, as if by calling Meteor.methods.
this._initServerMethods();
this._initAccountDataHooks();
// If autopublish is on, publish these user fields. Login service
// packages (eg accounts-google) add to these by calling
// addAutopublishFields. Notably, this isn't implemented with multiple
// publishes since DDP only merges only across top-level fields, not
// subfields (such as 'services.facebook.accessToken')
this._autopublishFields = {
loggedInUser: ['profile', 'username', 'emails'],
otherUsers: ['profile', 'username']
};
this._initServerPublications();
// connectionId -> {connection, loginToken}
this._accountData = {};
// connection id -> observe handle for the login token that this connection is
// currently associated with, or a number. The number indicates that we are in
// the process of setting up the observe (using a number instead of a single
// sentinel allows multiple attempts to set up the observe to identify which
// one was theirs).
this._userObservesForConnections = {};
this._nextUserObserveNumber = 1; // for the number described above.
// list of all registered handlers.
this._loginHandlers = [];
setupUsersCollection(this.users);
setupDefaultLoginHandlers(this);
setExpireTokensInterval(this);
this._validateLoginHook = new Hook({ bindEnvironment: false });
this._validateNewUserHooks = [
defaultValidateNewUserHook.bind(this)
];
this._deleteSavedTokensForAllUsersOnStartup();
this._skipCaseInsensitiveChecksForTest = {};
};
Meteor._inherits(AccountsServer, AccountsCommon);
var Ap = AccountsServer.prototype;
///
/// CURRENT USER
///
// @override of "abstract" non-implementation in accounts_common.js
Ap.userId = function () {
// This function only works if called inside a method. In theory, it
// could also be called from publish statements, since they also
// have a userId associated with them. However, given that publish
// functions aren't reactive, using any of the infomation from
// Meteor.user() in a publish function will always use the value
// from when the function first runs. This is likely not what the
// user expects. The way to make this work in a publish is to do
// Meteor.find(this.userId()).observe and recompute when the user
// record changes.
var currentInvocation = DDP._CurrentInvocation.get();
if (!currentInvocation)
throw new Error("Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.");
return currentInvocation.userId;
};
///
/// LOGIN HOOKS
///
/**
* @summary Validate login attempts.
* @summary Constructor for the `Accounts` namespace on the server.
* @locus Server
* @param {Function} func Called whenever a login is attempted (either successful or unsuccessful). A login can be aborted by returning a falsy value or throwing an exception.
* @class
* @extends AccountsCommon
* @instancename accountsServer
* @param {Object} server A server object such as `Meteor.server`.
*/
Ap.validateLoginAttempt = function (func) {
// Exceptions inside the hook callback are passed up to us.
return this._validateLoginHook.register(func);
AccountsServer = class AccountsServer extends AccountsCommon {
// Note that this constructor is less likely to be instantiated multiple
// times than the `AccountsClient` constructor, because a single server
// can provide only one set of methods.
constructor(server) {
super();
this._server = server || Meteor.server;
// Set up the server's methods, as if by calling Meteor.methods.
this._initServerMethods();
this._initAccountDataHooks();
// If autopublish is on, publish these user fields. Login service
// packages (eg accounts-google) add to these by calling
// addAutopublishFields. Notably, this isn't implemented with multiple
// publishes since DDP only merges only across top-level fields, not
// subfields (such as 'services.facebook.accessToken')
this._autopublishFields = {
loggedInUser: ['profile', 'username', 'emails'],
otherUsers: ['profile', 'username']
};
this._initServerPublications();
// connectionId -> {connection, loginToken}
this._accountData = {};
// connection id -> observe handle for the login token that this connection is
// currently associated with, or a number. The number indicates that we are in
// the process of setting up the observe (using a number instead of a single
// sentinel allows multiple attempts to set up the observe to identify which
// one was theirs).
this._userObservesForConnections = {};
this._nextUserObserveNumber = 1; // for the number described above.
// list of all registered handlers.
this._loginHandlers = [];
setupUsersCollection(this.users);
setupDefaultLoginHandlers(this);
setExpireTokensInterval(this);
this._validateLoginHook = new Hook({ bindEnvironment: false });
this._validateNewUserHooks = [
defaultValidateNewUserHook.bind(this)
];
this._deleteSavedTokensForAllUsersOnStartup();
this._skipCaseInsensitiveChecksForTest = {};
}
///
/// CURRENT USER
///
// @override of "abstract" non-implementation in accounts_common.js
userId() {
// This function only works if called inside a method. In theory, it
// could also be called from publish statements, since they also
// have a userId associated with them. However, given that publish
// functions aren't reactive, using any of the infomation from
// Meteor.user() in a publish function will always use the value
// from when the function first runs. This is likely not what the
// user expects. The way to make this work in a publish is to do
// Meteor.find(this.userId()).observe and recompute when the user
// record changes.
var currentInvocation = DDP._CurrentInvocation.get();
if (!currentInvocation)
throw new Error("Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.");
return currentInvocation.userId;
}
///
/// LOGIN HOOKS
///
/**
* @summary Validate login attempts.
* @locus Server
* @param {Function} func Called whenever a login is attempted (either successful or unsuccessful). A login can be aborted by returning a falsy value or throwing an exception.
*/
validateLoginAttempt(func) {
// Exceptions inside the hook callback are passed up to us.
return this._validateLoginHook.register(func);
}
/**
* @summary Set restrictions on new user creation.
* @locus Server
* @param {Function} func Called whenever a new user is created. Takes the new user object, and returns true to allow the creation or false to abort.
*/
validateNewUser(func) {
this._validateNewUserHooks.push(func);
}
///
/// CREATE USER HOOKS
///
/**
* @summary Customize new user creation.
* @locus Server
* @param {Function} func Called whenever a new user is created. Return the new user object, or throw an `Error` to abort the creation.
*/
onCreateUser(func) {
if (this._onCreateUserHook) {
throw new Error("Can only call onCreateUser once");
}
this._onCreateUserHook = func;
}
};
var Ap = AccountsServer.prototype;
// Give each login hook callback a fresh cloned copy of the attempt
// object, but don't clone the connection.
//
@@ -1161,24 +1192,6 @@ Meteor.startup(function () {
});
});
///
/// CREATE USER HOOKS
///
/**
* @summary Customize new user creation.
* @locus Server
* @param {Function} func Called whenever a new user is created. Return the new user object, or throw an `Error` to abort the creation.
*/
Ap.onCreateUser = function (func) {
if (this._onCreateUserHook) {
throw new Error("Can only call onCreateUser once");
} else {
this._onCreateUserHook = func;
}
};
// XXX see comment on Accounts.createUser in passwords_server about adding a
// second "server options" argument.
function defaultCreateUserHook(options, user) {
@@ -1249,15 +1262,6 @@ Ap.insertUserDoc = function (options, user) {
return userId;
};
/**
* @summary Set restrictions on new user creation.
* @locus Server
* @param {Function} func Called whenever a new user is created. Takes the new user object, and returns true to allow the creation or false to abort.
*/
Ap.validateNewUser = function (func) {
this._validateNewUserHooks.push(func);
};
// Helper function: returns false if email does not match company domain from
// the configuration.
Ap._testEmailDomain = function (email) {

View File

@@ -5,6 +5,7 @@ Package.describe({
Package.onUse(function (api) {
api.use('underscore', ['client', 'server']);
api.use('ecmascript', ['client', 'server']);
api.use('ddp-rate-limiter');
api.use('localstorage', 'client');
api.use('tracker', 'client');

View File

@@ -92,6 +92,8 @@ AccountsTest = {
* [`Accounts.sendResetPasswordEmail`](#accounts_sendresetpasswordemail).
* This function should be called in top-level code, not inside
* `Meteor.startup()`.
* @memberof! Accounts
* @name onResetPasswordLink
* @param {Function} callback The function to call. It is given two arguments:
*
* 1. `token`: A password reset token that can be passed to
@@ -116,6 +118,8 @@ Ap.onResetPasswordLink = function (callback) {
* [`Accounts.sendVerificationEmail`](#accounts_sendverificationemail).
* This function should be called in top-level code, not inside
* `Meteor.startup()`.
* @memberof! Accounts
* @name onEmailVerificationLink
* @param {Function} callback The function to call. It is given two arguments:
*
* 1. `token`: An email verification token that can be passed to
@@ -141,6 +145,8 @@ Ap.onEmailVerificationLink = function (callback) {
* [`Accounts.sendEnrollmentEmail`](#accounts_sendenrollmentemail).
* This function should be called in top-level code, not inside
* `Meteor.startup()`.
* @memberof! Accounts
* @name onEnrollmentLink
* @param {Function} callback The function to call. It is given two arguments:
*
* 1. `token`: A password reset token that can be passed to