Not receiving mail with "adminCreateUser" function in AWS Cognito - node.js

I am trying to create User with adminCreateUser function, but I am not receiving temporary password on my mail id.
var RegisterUser = exports.RegisterUser = function (data) {
var params = {
UserPoolId: __MY_POOL_ID__,
Username: data.username,
DesiredDeliveryMediums: [
'EMAIL'
],
ForceAliasCreation: false,
MessageAction: 'SUPPRESS',
TemporaryPassword: 'tempPassword1',
UserAttributes: [
{
Name: 'email',
Value: data.email
},
{
Name: 'name',
Value: data.name
}
]
};
return new Promise((res, rej) => {
_CISP.adminCreateUser(params, function (err, data) {
if (err) {
rej(err)
}
else {
res(data)
}
});
})
}
Case 1: When I am trying to creating a user from the Cognito AWS Console, then I am receiving the temporary password. (It is working)
Case 2: When I am trying to create a user using Cognito Admin API, can not get password. (Not working) Any idea?

Remove
MessageAction: 'SUPPRESS'
That option prevents messages from sending: https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html#CognitoUserPools-AdminCreateUser-request-MessageAction

Related

How can I verify a user attribute in AWS Cognito?

I'm trying to verify a user's email by calling the verifyAttribute method.
I am able to authenticate and get a JWT response - and with that I can do the following:
const { email, phone, accessToken } = verifyUserAttributesDto;
const getUser = await CognitoService.getUser(accessToken);
const attributes = getUser.UserAttributes.reduce(
(acc, { Name, Value }) => ({ ...acc, [Name]: Value }),
{},
);
console.log(attributes);
........
{
sub: '5f04a73b-...',
email_verified: 'false',
phone_number_verified: 'false',
phone_number: '+12222222222',
given_name: 'First',
family_name: 'Last',
email: 'example#email.com'
}
So I know I'm able to access the user.
Later I do:
const cognitoUser = new AmazonCognitoIdentity.CognitoUser({
Username: attributes.email,
Pool: this.userPool,
});
...
CognitoUser {
username: 'example#email.com',
pool: CognitoUserPool {
...
I believe I have an instance of a CognitoUser here, but maybe I don't; maybe that's the problem.
If I do:
return new Promise(function (resolve, reject) {
return cognitoUser.verifyAttribute(attribute, accessToken, {
onSuccess: (success) => {
console.log(success);
resolve(success);
},
onFailure: (err) => {
console.log(err);
reject(err);
},
});
});
The response I get back is:
ERROR [ExceptionsHandler] User is not authenticated
I have verified in the AWS console that the confirmation status for the user is confirmed and the account status is enabled.
If I've got a valid JWT, and am able to "get" the user, why am I getting that error?
It's painfully obvious I'm not sure what I'm doing. I got this working due to:
I wasn't providing the verification code
I was using the wrong identity provider (cognito vs. cognito user)
There are two methods needed to verify:
getUserAttributeVerificationCode
verifyUserAttribute
async getUserAttributeVerificationCode(
attribute: string,
accessTokenDto: AccessTokenDto,
) {
const { accessToken } = accessTokenDto;
const cognito = new AWS.CognitoIdentityServiceProvider();
try {
return await cognito
.getUserAttributeVerificationCode({
AccessToken: accessToken,
AttributeName: attribute,
})
.promise();
} catch (err) {
throw new BadRequestException(err.message);
}
}
async verifyUserAttribute(verifyUserAttributesDto: VerifyUserAttributesDto) {
const { email, phone, accessToken, verificationCode } =
verifyUserAttributesDto;
const cognito = new AWS.CognitoIdentityServiceProvider();
try {
if (email || phone) {
const attribute = email ? 'email' : 'phone';
return await cognito
.verifyUserAttribute({
AccessToken: accessToken,
AttributeName: attribute,
Code: verificationCode,
})
.promise();
}
} catch (err) {
throw new BadRequestException(err.message);
}
}
You'll first need to call getUserAttributeVerificationCode with a valid JWT. You'll then get sent a verification code (email/sms).
With that, you'll call verifyUserAttribute with all of the proper attributes.

Aws cognito create user by admin nodejs

I am using javascript sdk amazon-cognito-identity-js and i am trying to create a user in cognito in nodejs but error is coming
below is my code:-
var AWS = require("aws-sdk")
var params = {
UserPoolId: "id",
Username: req.body.username,
DesiredDeliveryMediums: ["EMAIL"],
ForceAliasCreation: false,
TemporaryPassword: req.body.password,
UserAttributes: [
{ Name: "name", Value: req.body.name },
{ Name: "email", Value: req.body.user_email}
],
};
let client = new AWS.CognitoIdentityServiceProvider();
client.adminCreateUser(params, function(err, data) {
if (err) {
console.log("EE",err);
// reject(err);
} else {
console.log("DDD",data);
//resolve(data);
}
})
But i am getting this error using the code:-
EE { UnknownError: Not Found at Request.extractError
(/var/task/node_modules/aws-sdk/lib/protocol/json.js:48:27) }
Please Help me Out to figure out this issue.
Here is the solution.
Pre-requirement
If you want to use the credential in aws-sdk (Manual Process)
1. Create IAM User and Assign a Cognito role to your user.
2. Generate Access Key and Secret Key for that user.
3. Use that Access Key and Secret Key in aws-sdk.
Like This,
let AWS = require("aws-sdk");
AWS.config.update({
accessKeyId: "YOURKEY",
secretAccessKey: "YOURSECRET",
region: "YOURREGION"
});
Create object of CognitoIdentityServiceProvider class
const COGNITO_CLIENT = new AWS.CognitoIdentityServiceProvider({
apiVersion: "2016-04-19",
region: "us-east-1"
});
var poolData = {
UserPoolId: "XXXXXXXXX",
Username: "kurulezomi#themailpro.net",
DesiredDeliveryMediums: ["EMAIL"],
TemporaryPassword: "Abc#321",
UserAttributes: [
{
Name: "email",
Value: "kuri#themailpro.net"
},
{
Name: "email_verified",
Value: "true"
}
]
};
COGNITO_CLIENT.adminCreateUser(poolData, (error, data) => {
console.log(error);
console.log(data);
callback(null, {
statusCode: 200,
body: JSON.stringify(data)
});
});
Or else you can directly assign IAM Role to your EC2 Instance in that case you do not need to set credentials in AWS.config Section.
ABOUT THIS NODE.JS EXAMPLE: This example works with the AWS SDK for JavaScript version 2 (v2).
Purpose:
admin-create-user.js demonstrates how an administrator can use Amazon Cognito to create a user.
Inputs:
USERPOOLID
EMAIL
AWS configuration
const AWS = require("aws-sdk");
AWS.config.update({
accessKeyId : "Your accessKeyId ",
secretAccessKey: "secretAccessKey",
});
CREATE COGNITO_CLIENT
const COGNITO_CLIENT = new AWS.CognitoIdentityServiceProvider({
apiVersion: "2022-10-03",
region: "us-east-1",
});
CREATE USER
const createUser = async (user) => {
try {
const { emailId, password } = user;
const cognitoParams = {
UserPoolId: userPoolId,
Username: emailId,
UserAttributes: [
{
Name: "email",
Value: emailId,
},
{
Name: "email_verified",
Value: "true",
},
],
TemporaryPassword: password || "Password#123456789",
};
console.log(cognitoParams.TemporaryPassword);
let response = await COGNITO_CLIENT.adminCreateUser(
cognitoParams
).promise();
console.log(JSON.stringify(response));
return "user created";
} catch (err) {
throw Error(err);
}
};

Do I need amazon-cognito-identity-js if I already have the aws-sdk (javascript)?

I have a javascript project where I use the aws-sdk. No I want to use amazon-cognito-identity-js. On the page it says:
Note that the Amazon Cognito AWS SDK for JavaScript is just a slimmed down version
of the AWS Javascript SDK namespaced as AWSCognito instead of AWS. It
references only the Amazon Cognito Identity service.
and indeed, I can for example create CognitoIdentityServiceProvider with:
CognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider();
But how do I do thinks like authenticate a user? According to the amazon-cognito-identity-js documentation:
authenticationDetails = new CognitoIdentityServiceProvider.AuthenticationDetails({Userame: ..., Password: ...});
cognitoUser.authenticateUser(authenticationDetails, ...)
But the CognitoIdentityServiceProvider object does not have a AuthenticationDetails property.
Do I have to do something different when I use the aws-sdk instead of amazon-cognito-identity-js?
Or is my assumption wrong, and I need both, the aws-sdk and amazon-cognito-identity-js?
No, you don't. You can login using aws-sdk like this:
const cognito = new aws.CognitoIdentityServiceProvider({ region });
cognito.adminInitiateAuth({
AuthFlow: 'ADMIN_NO_SRP_AUTH',
ClientId: clientId,
UserPoolId: poolId,
AuthParameters: {
USERNAME: email,
PASSWORD: password,
},
});
For userName password authentication, it needs to have ADMIN_NO_SRP_AUTH.
I also added function to handle err and success. For more details about response and token sent in data, you can check was reference.
const cognito = new AWS.CognitoIdentityServiceProvider();
cognito.adminInitiateAuth({
AuthFlow: 'ADMIN_NO_SRP_AUTH',
ClientId: 'clientId',
UserPoolId: 'poolId'
AuthParameters: {
USERNAME: 'userName',
PASSWORD: 'password',
},
}, function(err, data) {
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
}
});
for any coming in the future
the following is what i did for register and login using
private cognito = new AWS.CognitoIdentityServiceProvider();
register:
public async register(event) {
try {
if(!this.validator.isObjectNotEmpty(event.body)){
throw new Error("you have to include body to insert into DB !!");
}
const usermodel = event.body;
if (this.validator.isEmailNotValid(usermodel)) {
throw new Error("Not Valid username or password");
}
const email = usermodel.email.toLowerCase();
const password = usermodel.password;
const createUserParams = {
UserPoolId: Cognito_User_Pool, // From Cognito dashboard 'Pool Id'
Username: email,
MessageAction: "SUPPRESS", // Do not send welcome email
TemporaryPassword: password,
};
const user = await this.cognito.adminCreateUser(createUserParams).promise();
this.logger.info("created user: ",user);
const initiateAuthParams = {
AuthFlow: "ADMIN_USER_PASSWORD_AUTH",
ClientId: Cognito_User_Pool_Client,
UserPoolId: Cognito_User_Pool,
AuthParameters: {
USERNAME: email,
PASSWORD: password
}
};
const challengesResponse = await this.cognito.adminInitiateAuth(initiateAuthParams).promise();
this.logger.info("challengesResponse: ",challengesResponse);
const userPasswordParams = {
Password: password,
UserPoolId: Cognito_User_Pool,
Username: email,
Permanent: true
};
return this.cognito.adminSetUserPassword(userPasswordParams).promise();
} catch (error) {
console.log("error: ", error);
throw error;
}
}
login
public async login(event) {
try {
this.logger.info("login - event: ",JSON.stringify(event));
this.logger.info("register - Cognito_User_Pool: ",Cognito_User_Pool);
this.logger.info("register - Cognito_User_Pool_Client: ",Cognito_User_Pool_Client);
if(!this.validator.isObjectNotEmpty(event.body)){
throw new Error("you have to include body to insert into DB !!");
}
const usermodel = event.body;
if (this.validator.isEmailNotValid(usermodel)) {
throw new Error("Not Valid username or password");
}
const email = usermodel.email.toLowerCase();
const password = usermodel.password;
const initiateAuthParams = {
AuthFlow: "ADMIN_USER_PASSWORD_AUTH",
ClientId: Cognito_User_Pool_Client,
UserPoolId: Cognito_User_Pool,
AuthParameters: {
USERNAME: email,
PASSWORD: password
}
};
return await this.cognito.adminInitiateAuth(initiateAuthParams).promise();
} catch (error) {
console.log("error: ", error);
throw error;
}
}
the login function return response like this:
"tokenObj": {
"ChallengeParameters": {},
"AuthenticationResult": {
"AccessToken": "eyJraWQiOiI1ZFN5R0tEUFE2WnhTbzJ4N01QTXpxaVRPNXZoK3p5NkJaOFZhRzV1M0Z3PSIsImFsZyI6IlJTMjU2In0.eyJvcmlnaW5fanRpIjoiMGYzY2RmZTItZTM3Zi00NGRiLWJiMWQtMDIzYjFiZTdlZGVjIiwic3ViIjoiZWJjN2M4YzctZjllYS00MTMxLTgxNDQtNjdkM2ZmYzg1ZTdlIiwiZXZlbnRfaWQiOiJhYWJhNzgyZi1iZTVhLTQxMjItYjljYS0yNjg5NTY2ZDVkMTgiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6ImF3cy5jb2duaXRvLnNpZ25pbi51c2VyLmFkbWluIiwiYXV0aF90aW1lIjoxNjM4MTI0NTY3LCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtd2VzdC0yLmFtYXpvbmF3cy5jb21cL3VzLXdlc3QtMl9vVmFnb3hFd0wiLCJleHAiOjE2MzgxMjgxNjcsImlhdCI6MTYzODEyNDU2NywianRpIjoiZjE0MTBjMGEtOWM4ZS00YjMzLWJkMjEtNmQ1ZDIwYzJiNDU5IiwiY2xpZW50X2lkIjoiNnVvc2dxNzNtYjFlYmk5c3BnbDV0N282Z2QiLCJ1c2VybmFtZSI6ImViYzdjOGM3LWY5ZWEtNDEzMS04MTQ0LTY3ZDNmZmM4NWU3ZSJ9.4vswc6-ei6SFlbN0k_C8PAtmEK294oFfylYZW3hhmHqMT49d_JWdDPR8XgA7n5cLqtLJsiG4PVh9SyxdirpUTmC0yra2GZejNWP8eVHG9-JUq_xXQ81a8AYEb1KZJBAv0j2F1ZLuCFaiFvbOBFEGSlJXp4e2bLz-NWlSbEAUbxZV5BKrRmZEeXJUxw_DO5R30SG1D2qcOn_1mnbdfTH-W0ZMuuMJsHWQBsO7QEtyMI62XG35WRDijzzMr6ekbLyIQ7J77dYcsmTdR6S5nTNWE1yrGYtkdxk2x35nYob06PAWdnWL5OK2G1aiJ97BMvM65VtjX8VQZbAoalIII-PbCA",
"ExpiresIn": 3600,
"TokenType": "Bearer",
"RefreshToken": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.FKN-KM415xH-TioTkKjmoy_NV1AssBq9GlkweHAK7TuYzMeI_qMfeL00Qv6MiOPFMJ6UG7cLKfJjkdyI1vK09p9lk5_wor3FoCX1Dvt3DK3SKzeyqW6ULQL1IQmNunPhpC3sARom0q74YxSaQKdF_6PgDjNnf0-aI1XGkZYZUw69BZGQDVobTx8nR_Lf6srF622s0JuhaClDfvIgqjZun7AIFlxgNUKL6uuMgmSrRJm7GvAqAnTQpmQD2sdz6D3fWeoVja8LRpc_QMbZPhjZmOoRrQJ3VA-m0M0TsNMvQSw6px-WS-hMUH4RFeFasrbmoiUKIU8-MXltyPVltoy0qg.dHBgjs1NAOAROzD6.vi7DzrqzLkuHGuuGY1vNZaYmdDp0-EliwxTtEOaMboVlMCm9KZv0tU06ovQ9Z2CbplqJdEaAu-YZSG3Oeagqj5JJ2-739C0yvA0J_qE2Ehn5gCUMuiPPOjakIczOcI8wcRItsTGqt1GFmyq4DSnX-pjc9GG2QWpgmcsoDyxodIv1wTu7YN15cGK0YN_xSKolcCn04gCzqXCDkQyUqX-Sr7QqD2o-aQC1ynmKz1tJGxRM3I6rzbcRZkNvUK02wSIUMeY05hJNAdKBItIE0t45Sk5_EV3mzLgebC39Q6z-kRKNQwhyQKrcXg71aRJGjD3HH61VEoops4wcgRCmNnI7u-9JjJic_SDU_Fw-9W1L8BxZZKPsJrjOvJroDFc1xX2njgeivo6ZpRWTg3nQphMTqJFSYHnWcEmw3EW1uUhN7e1J2bdGuebW40Opf5zMXo2V4-OBI3UMxTOVZEPit4g3yLDHQDAfPZllPPRf5H8Kf1Qe54fEq77sKb32I5PH7t-7xQ79iE5KX6BZjsLjwHMAlGNtS7WSE-U0yAsjUFFH8pA7eYR5ysz3o9L7jJsNCyNb06YU_QX5mozGlspLMNs4qpUcWkFGhSNG6qTRMREpzRfELU82Dc-LirJ1425zPQNsQV1CGGtlDoXVA-RCIgnMG1hslfpIllKm_IH-5yyPMfH2UFdr7jdRjt9crFyFu9ktGkHjnAqH_ZUcueL0q_vrIqmkGcBcrQQRY9jCSC4VNeGhKe9ecJciAHUCktkZuut5yI0De0hXANoaoxeIucJlox57nxHnQTD0Q0LEuXvfqG9M9sNdB4GGrt1rYR58ZWa8zc5udoKDMxvrb6GEeDI1co2mLEt3XghjcJBJqB8nqwofXZDxiDSXQ53R9L5U8wDlxhxZxPMDKFL6wu4gqDjw4m60R8mOvfOI2Gz_yelqfk5CxD6Ts_HVbv9TRbsV0adQ4S8n5Cktf5miWUtFCOktruS2_fKfB6TF1yzisgxQpJFD7B1qdTcBu0N82KgHrljoBlVKiwGdalL52H-cJkNkagZIBQYXvlvkBrbsSNAp1CeUiqXbddHku47RNjXSPUMN1aoHdEL14_7zbaPYBMxgEsmqjP67B45QKmTyDDsOkf8aSdAWYFKvj3c_4Cn_LczLU-YcuzE4UZvd6BQK70MiKBIsd3DU4rdKTDjAsN73mJ_U-_8r34jocny4rzbO_NostPjgqUugoO2bGhfr_PUgXb7sm_wrKlvjFnUcOLpQSBxlZL_z25e8vZokRn4QiNa83_VG6xyp77-c_DQqLC3RdwXOyRmCEXkM2D10cBNQpkAzCBMyP9FO3mJZcQ.aAJlWM76hqlRprKY8P_Qmw",
"IdToken": "eyJraWQiOiJoWmpBMXl1d2JjT1lyNks5dnhQc2ZKVDhXSHRrYm51WmZlTURlK0dBbWR3PSIsImFsZyI6IlJTMjU2In0.eyJvcmlnaW5fanRpIjoiMGYzY2RmZTItZTM3Zi00NGRiLWJiMWQtMDIzYjFiZTdlZGVjIiwic3ViIjoiZWJjN2M4YzctZjllYS00MTMxLTgxNDQtNjdkM2ZmYzg1ZTdlIiwiYXVkIjoiNnVvc2dxNzNtYjFlYmk5c3BnbDV0N282Z2QiLCJldmVudF9pZCI6ImFhYmE3ODJmLWJlNWEtNDEyMi1iOWNhLTI2ODk1NjZkNWQxOCIsInRva2VuX3VzZSI6ImlkIiwiYXV0aF90aW1lIjoxNjM4MTI0NTY3LCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtd2VzdC0yLmFtYXpvbmF3cy5jb21cL3VzLXdlc3QtMl9vVmFnb3hFd0wiLCJjb2duaXRvOnVzZXJuYW1lIjoiZWJjN2M4YzctZjllYS00MTMxLTgxNDQtNjdkM2ZmYzg1ZTdlIiwiZXhwIjoxNjM4MTI0ODY3LCJpYXQiOjE2MzgxMjQ1NjcsImp0aSI6ImRmMzVlZWQ1LWZjNGItNDBlZS1hYWEwLTYxNTViZWNiNjIyNyIsImVtYWlsIjoidGVzdDJAdGVzdC5jb20ifQ.L9nNSlcQakRfVpAo-bf9jnXFrhov8iD9j3R2UI7x5eUT42OBrvSdEk3Y2JtFKQt1FpxBFLqtWCRyY0Wxlcq3MzZE04zIFBC02WmV24vF1QS9TxpBYAm8NkyNoW-7Lqe7CIWhK_DHMxSRpzo87txmwpID6xwd9JOlZG04L76hkXr0_2JgM2KuvB0lKL0v4heHK8e2ht_VuKBPNpVvMIbIA2xN22LRhivfG8EMeHmF3jhhQYggi1Pczb2WEviPUqebmLhdvjJpHC9OMVhvN4GMcr0JVv-GepxSCrNSFoXPDNZaznJbDJW0Zt3xY9bWek_l62v1Wm0a1h7V7nxw8a0Csw"
}
}
}

React-Facebook-Login and Node.js Express

I'm using React with Redux on the client and Node.js with Express as an Rest API on the server. I've implemented a local login with passport but I also wan't to implement social login, such as Facebook login.
I'm using react-facebook-login where the user gets authenticated and some information are returned in the response, including AccessToken, Email, Name, ID, etc. I then want to send these information to the server (running on another port) and save the user there to the database (MongoDb). This is how the user schema is structured:
const userSchema = Schema({
local: {
email: {
type: String,
unique: true,
},
password: String,
name: String
},
facebook: {
id: String,
token: String,
email: String,
name: String
},
...
After a user has been saved to the database I return a JWTtoken to the client with this function:
const tokenForUser = (user) => {
const timestamp = new Date().getTime();
return jwt.encode({ sub: user._id, iat: timestamp }, SECRET);
};
The token can then be used to authenticate.
OK, here is the real problem. When creating a Facebook user I first check if the user exists, if not then create him:
const facebookSignIn = (model, cb) => {
User.findOne({ 'facebook.id': model.id }, (err, docs) => {
if (err) {
return cb({ 'status': HTTP_INTERNAL_SERVER_ERROR,
'message': { error: 'Unable to search for an user due to an unknown error' } });
} else if (docs) {
return cb(null, { token: tokenForUser(docs) });
}
const user = new User({
facebook: {
id: model.id,
token: model.accessToken,
email: model.email,
name: model.name
}
});
user.save((err) => {
if (err) {
if (err.name === VALIDATION_ERROR) {
return cb({ 'status': HTTP_PRECONDITION_FAILED,
'message': { error: Object.keys(err.errors).map(e => `${err.errors[e].message} `) } });
}
return cb({ 'status': HTTP_INTERNAL_SERVER_ERROR,
'message': { error: 'Unable to save user due to an unknown error' } });
}
return cb(null, { token: tokenForUser(user) });
});
});
};
If a user has been authenticated (exists in the database) then there can be a request sent to the server only containing his/her Facebook ID. Then the user will be allowed to enter the website and will be returned a JWTtoken.
I need to authenticate the accessToken from the user when he/she is authenticated on the server. How can I authenticate the accessToken on the server by bypassing CORS?
Thanks in advance!
The solution was to validate the accessToken with facebook graph by sending a GET request to https://graph.facebook.com/me from the server, containing the accessToken.

Node: How to change keys stored in LevelDB for accounts using the Accountdown module

I'm using accountdown, with accountdown-basic as the plugin (https://www.npmjs.com/package/accountdown), and each account is stored using the LevelDB (https://www.npmjs.com/package/level) key-value store. Right now, the key for each account is a username:
{ key: 'user1',
value:
{ admin: true,
email: 'user1#gmail.com',
username: 'user1',
color: 'rgb(155, 26, 2)' } }
{ key: 'test',
value:
{ admin: true,
color: 'rgb(58, 48, 48)',
email: 'test#test.com',
username: 'test' } }
{ key: 'test2',
value:
{ admin: false,
color: 'rgb(75, 77, 154)',
email: 'test2#test.com',
username: 'test2' } }
but I want to use uuid's instead of a username:
{ key: '03b49d10-ee20-11e4-b966-bfcbf13ae8c2',
value:
{ admin: true,
email: 'user1#gmail.com',
username: 'user1',
color: 'rgb(155, 26, 2)' } }
{ key: '0485a8b0-ee20-11e4-b966-bfcbf13ae8c2',
value:
{ admin: true,
color: 'rgb(58, 48, 48)',
email: 'test#test.com',
username: 'test' } }
{ key: '04eea3b0-ee20-11e4-b966-bfcbf13ae8c2',
value:
{ admin: false,
color: 'rgb(75, 77, 154)',
email: 'test2#test.com',
username: 'test2' } }
How can I change these keys on existing accounts (ie perform a migration)? I'm stuck in my attempt to delete each account and re-create the accounts using uuid as the key, because I must provide the raw password string for my account-basic plugin. It seems that I only have access to each account's salted password's hash. Any suggestions? I'm happy to provide more clarification.
Here is my attempt at writing a script that checks whether each account starts with a uuid, and if so, creates a new account using the uuid as key and deletes the existing account:
var level = require('level');
var uuid = require('uuid').v1;
var each = require('each-async');
var accountdown = require('accountdown');
var sublevel = require('subleveldown');
var accountHandler = require('../handlers/accounts');
var db = level(__dirname + '/../data/db', { valueEncoding: 'json' });
var sheets = require('../models/sheets')(db);
var accountdownAccounts = accountdown(sublevel(db, 'accounts'), {
login: { basic: require('accountdown-basic') }
});
var accountStream = accountdownAccounts.list();
var accountList = [];
// Convert our stream of accounts into a list:
accountStream
.on('data', function (data) {
accountList.push(data);
})
.on('error', function (err) {
return console.log(err);
})
.on('end', function () {
var uuidRegex = /^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$/;
// Iterate through the list of accounts, deleting and re-creating all accounts that do not have a uuid as a key
accountList.forEach(function (account) {
// example of account:
// { key: 'user1',
// value:
// { admin: true,
// email: 'user1#gmail.com',
// username: 'user1',
// color: 'rgb(155, 26, 2)' }
// }
if (!uuidRegex.test(account.key) ) {
// Since the account key dd a new account using the uuid key, and remove old account
accountdownAccounts.get(account.key, function (err, accountValue) {
if (err) return console.log("error retrieving test account:", err);
var opts = {
login: {
basic: {
username: accountValue.username,
password: password // I cannot access the password to create a new account!!!
}
},
value: accountValue
};
accountdownAccounts.create(uuid(), opts, function (err) {
if (err) return console.log("err while putting in new account:", err);
accountdownAccounts.remove(account.key, function (err) {
if (err) return console.log("err while deleting old account:", err);
});
});
});
} else {
console.log("Account is valid:", account);
}
});
});
I believe the only way to alter the key in a key-value store like levelDB is to delete and recreate the row.
That being said, accountdown-basic now has the ability to save accounts under an arbitrary key instead of the default username. (That option is fairly recent, implement just 2 days ago)

Resources