Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added AWS config and identity store #2208

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
93b2b58
aws setup
vikhyat187 Oct 6, 2024
b4598db
lint-fix
vikhyat187 Oct 8, 2024
16e8b37
fixed linting issues
vikhyat187 Oct 9, 2024
2857c15
Removed the flow to take credentials from .aws folder in local
vikhyat187 Oct 16, 2024
dafb8ec
resolving merge conflicts
vikhyat187 Oct 16, 2024
9edd8c3
Merge branch 'develop' into aws-config-setup
vikhyat187 Oct 16, 2024
bbf39dd
Merge branch 'develop' into aws-config-setup
vikhyat187 Oct 19, 2024
611625d
added unit tests for the code
vikhyat187 Oct 23, 2024
abb8a3c
Merge branch 'develop' into aws-config-setup
vikhyat187 Oct 23, 2024
d92a238
Merge branch 'develop' into aws-config-setup
vikhyat187 Oct 24, 2024
92f9a7f
Merge branch 'develop' into aws-config-setup
Achintya-Chatterjee Oct 25, 2024
68b63f1
Merge branch 'develop' into aws-config-setup
Achintya-Chatterjee Oct 25, 2024
e447b63
aws setup
vikhyat187 Oct 6, 2024
3b1e279
Revert "aws setup"
vikhyat187 Oct 26, 2024
08328a8
added integration tests
vikhyat187 Oct 26, 2024
952110c
refactored the route and removed console log
vikhyat187 Oct 26, 2024
87a2c76
Merge branch 'develop' into aws-config-setup
vikhyat187 Oct 29, 2024
81bf324
updated the integration tests and added fixture
vikhyat187 Nov 1, 2024
6a72bd3
changes
vikhyat187 Nov 2, 2024
778c4cc
resolving PR comments
vikhyat187 Nov 5, 2024
63eca88
Merge branch 'develop' into aws-config-setup
vikhyat187 Nov 6, 2024
4edf99d
resolving PR comments
vikhyat187 Nov 6, 2024
fde42ff
Merge branch 'aws-config-setup' of https://github.com/vikhyat187/webs…
vikhyat187 Nov 6, 2024
1b9b46a
Fixed test cases and added test case for User not found case
vikhyat187 Nov 7, 2024
e7a0dba
added feature flag to backend API and updated test cases
vikhyat187 Nov 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions config/custom-environment-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ module.exports = {
__name: "PORT",
__format: "number",
},

aws: {
region: {
__name: "AWS_REGION",
},
access_key: {
__name: "AWS_ACCESS_KEY",
},
secret_key: {
__name: "AWS_SECRET_KEY",
},
identity_store_id: {
__name: "IDENTITY_STORE_ID",
},
},

enableFileLogs: {
__name: "ENABLE_FILE_LOGS",
__format: "boolean",
Expand Down
7 changes: 7 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
org: "Real-Dev-Squad",
},

aws: {
region: "<aws-region>",
access_key: "<aws-access-key>",
secret_key: "<aws-secret-key>",
identity_store_id: "<identity-store-id>",
},

Comment on lines +23 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How to add env keys, please fix this part?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't get this part, do you suggest that the content from production.js cannot be stored in the Github secrets / secrets at the deployment time.
@prakashchoudhary07

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check how new env keys are added, and update the code accordingly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure let me check once.

githubOauth: {
clientId: "<clientId>",
clientSecret: "<clientSecret>",
Expand Down Expand Up @@ -66,7 +73,7 @@
},

cors: {
allowedOrigins: /(https:\/\/([a-zA-Z0-9-_]+\.)?realdevsquad\.com$)/, // Allow realdevsquad.com, *.realdevsquad.com

Check warning on line 76 in config/default.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Unsafe Regular Expression
},

userToken: {
Expand Down
2 changes: 2 additions & 0 deletions constants/urls.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export const GITHUB_URL = "https://github.com";
export const PROFILE_SVC_GITHUB_URL = "https://github.com/Real-Dev-Squad/sample-profile-service";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be shared in response for the user to set their email address


module.exports = {
GITHUB_URL,
PROFILE_SVC_GITHUB_URL,
};
2 changes: 1 addition & 1 deletion constants/userDataLevels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const ACCESS_LEVEL = {

const ROLE_LEVEL = {
private: ["super_user"],
internal: ["super_user"],
internal: ["super_user", "cloudfare_worker"],
confidential: ["super_user"],
};

Expand Down
43 changes: 43 additions & 0 deletions controllers/awsAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { PROFILE_SVC_GITHUB_URL } from "../constants/urls";
import {addUserToGroup, createUser, fetchAwsUserIdByUsername} from "../utils/awsFunctions";
const dataAccess = require("../services/dataAccessLayer");
const userDataLevels = require('../constants/userDataLevels');
Comment on lines +3 to +4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any specific reason to use require here?
Above lines are using import instead of require

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argument of type '{ discordId: any; level: any; role: string; }' is not assignable to parameter of type '{ discordId?: any; id?: any; username?: any; usernames?: any; query?: any; userdata: any; level?: any; role?: any; userIds?: any; }'

It was returning an error like this on using the import, I guess this can be resolved by passing default values to the rest of the fields right?

Copy link
Contributor

@samarpan1738 samarpan1738 Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was returning an error like this on using the import, I guess this can be resolved by passing default values to the rest of the fields right?

No idea. I have very little experience with Typescript
@vikhyat187

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here @samarpan1738, @vinit717 can you help us here please

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vikhyat187
I think we aren't able to use import properly with ../services/dataAccessLayer and ../constants/userDataLevels because they are using module.exports (which is CJS style) and import is ES6 modules way of importing


export const addUserToAWSGroup = async (req, res) => {
const { groupId, userId } = req.body;

try {
const userInfoData = await dataAccess.retrieveUsers({ discordId: userId, level: userDataLevels.ACCESS_LEVEL.INTERNAL, role: 'cloudfare_worker'});
if (!userInfoData.userExists) {
return res.status(400).json({ error: "User not found" });
} else if(!userInfoData.user.email) {
return res.status(400).json({ error: `User email is required to create an AWS user. Please update your email by setting up Profile service, url : ${PROFILE_SVC_GITHUB_URL}` });
Comment on lines +12 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use res.boom?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Prakash, I tried returning the response using the res.boom, but in the discord slash commands repo, while parsing this response and storing in variable, the variable was showing as Unkown

Copy link
Contributor Author

@vikhyat187 vikhyat187 Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the custom error message is not coming in the discord slash commands service, have tested with this change only bad request is coming in error message

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


      return res.boom.badRequest(`User email is required to create an AWS user. Please update your email by setting up Profile service, url : ${PROFILE_SVC_GITHUB_URL}` );

The response is Response {
  status: 400,
  statusText: 'Bad Request',
  headers: Headers(16) {
    'access-control-allow-credentials' => 'true',
    'cache-control' => 'private, max-age=0',
    'connection' => 'keep-alive',
    'content-length' => '217',
    'content-type' => 'application/json; charset=utf-8',
    'cross-origin-opener-policy' => 'same-origin',
    'cross-origin-resource-policy' => 'same-origin',
    'date' => 'Tue, 05 Nov 2024 15:12:54 GMT',
    'etag' => 'W/"d9-C1COlx1fZu9TxhTRp1pjlpMfeAs"',
    'keep-alive' => 'timeout=5',
    'origin-agent-cluster' => '?1',
    'strict-transport-security' => 'max-age=15552000; includeSubDomains',
    'vary' => 'Origin',
    'x-content-type-options' => 'nosniff',
    'x-frame-options' => 'SAMEORIGIN',
    'x-permitted-cross-domain-policies' => 'none',
    [immutable]: true
  },
  ok: false,
  redirected: false,
  url: 'http://localhost:3000/aws-access',
  webSocket: null,
  cf: undefined,
  body: ReadableStream {
    locked: false,
    [state]: 'readable',
    [supportsBYOB]: true,
    [length]: 217n
  },
  bodyUsed: false
}

Comment on lines +12 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: can we only have one return?

}

let awsUserId = await fetchAwsUserIdByUsername(userInfoData.user.username);

let userCreationResponse = null;

if (awsUserId === null){
// We need to create the user in AWS before and then fetch its Id
userCreationResponse = await createUser(userInfoData.user.username, userInfoData.user.email);
awsUserId = userCreationResponse.UserId;
}

let userAdditionResponse = await addUserToGroup(groupId, awsUserId)

if (userAdditionResponse.conflict){
return res.status(200).json({
message: `User ${userId} is already part of the AWS group, please try signing in.`
})
}

if (userAdditionResponse)
return res.status(200).json({
message: `User ${userId} successfully added to group ${groupId}.`
});
} catch (error) {
logger.error(`Error in adding user - ${userId} to AWS group - ${groupId} error - ${error}`);
throw error;
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"tdd:watch": "sh scripts/tests/tdd.sh"
},
"dependencies": {
"@aws-sdk/client-identitystore": "^3.665.0",
"@types/nodemailer": "^6.4.15",
"axios": "1.7.2",
"cloudinary": "2.0.3",
Expand Down
8 changes: 8 additions & 0 deletions routes/awsAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import express from "express"
import { addUserToAWSGroup } from "../controllers/awsAccess";
const router = express.Router();
const { verifyDiscordBot } = require("../middlewares/authorizeBot");

router.post("", verifyDiscordBot, addUserToAWSGroup);
Dismissed Show dismissed Hide dismissed

module.exports = router;
1 change: 1 addition & 0 deletions routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import express from "express";
const app = express.Router();
import { devFlagMiddleware } from "../middlewares/devFlag";

app.use("/aws-access", devFlagMiddleware, require("./awsAccess"))
app.use("/answers", require("./answers"));
app.use("/auctions", require("./auctions"));
app.use("/arts", require("./arts"));
Expand Down
7 changes: 7 additions & 0 deletions test/config/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ module.exports = {
clientId: "clientId",
clientSecret: "clientSecret",
},
aws: {
region: "us-east-1",
access_key: "test-access-key",
secret_key: "test-secret-key",
identity_store_id: "test-identity-store-id",
},

firestore: `{
"type": "service_account",
"project_id": "test-project-id-for-emulator",
Expand Down
1 change: 0 additions & 1 deletion test/fixtures/user/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ module.exports = () => {
twitter_id: "whatifi",
discordJoinedAt: "2023-04-06T01:47:34.488000+00:00",
phone: "1234567891",
email: "abc1@gmail.com",
picture: {
publicId: "profile/mtS4DhUvNYsKqI7oCWVB/aenklfhtjldc5ytei3ar",
url: "https://res.cloudinary.com/realdevsquad/image/upload/v1667685133/profile/mtS4DhUvNYsKqI7oCWVB/aenklfhtjldc5ytei3ar.jpg",
Expand Down
149 changes: 149 additions & 0 deletions test/integration/awsAccess.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import chai, {expect} from "chai";
import sinon from 'sinon';
import chaiHttp from 'chai-http';
import * as awsFunctions from '../../utils/awsFunctions';
import bot from "../utils/generateBotToken";
import { PROFILE_SVC_GITHUB_URL } from '../../constants/urls';

const app = require("../../server");
const userData = require("../fixtures/user/user")();
const authorizeBot = require("../../middlewares/authorizeBot");
const addUser = require("../utils/addUser");
const cleanDb = require("../utils/cleanDb");
const { CLOUDFLARE_WORKER } = require("../../constants/bot")

chai.use(chaiHttp);

describe('addUserToAWSGroup', function(){
let req: any;
const AWS_ACCESS_API_URL = `/aws-access?dev=true`

beforeEach(async () => {
await addUser(userData[0]);
await addUser(userData[1]);
sinon.restore();
req = {
headers: {},
};
const jwtToken = bot.generateToken({ name: CLOUDFLARE_WORKER });
req.headers.authorization = `Bearer ${jwtToken}`;
})

afterEach(async () => {
await cleanDb();
});

it('should return 400 and user not found with wrong discord Id passed', function(done){
const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '3000230293'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(400);
expect(res.body).to.have.property('error')
.that.equals(`User not found`);
return done();
})
});

it('should return 400 when user email is missing', function(done) {
const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '1234567890'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(400);
expect(res.body).to.have.property('error')
.that.equals(`User email is required to create an AWS user. Please update your email by setting up Profile service, url : ${PROFILE_SVC_GITHUB_URL}`);
return done();
});
});


it("Should create user and add to group, if the user is not present in AWS already", function(done){
sinon.stub(awsFunctions, "createUser").resolves({ UserId: "new-aws-user-id" });
sinon.stub(awsFunctions, "addUserToGroup").resolves({ conflict: false });
sinon.stub(awsFunctions, "fetchAwsUserIdByUsername").resolves(null);

const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '12345'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(200);
expect(res.body).to.have.property('message',
`User 12345 successfully added to group test-group-id.`
);
return done();
});
});

it("Should add the user to the group if the user is already part of AWS account", function(done){
sinon.stub(awsFunctions, "addUserToGroup").resolves({ conflict: false });
sinon.stub(awsFunctions, "fetchAwsUserIdByUsername").resolves("existing-user-id-123");

const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '12345'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(200)
expect(res.body).to.have.property('message',
'User 12345 successfully added to group test-group-id.'
);
return done();
});
});

it("Should return the signin URL if the user is already added to the group", function(done) {
sinon.stub(awsFunctions, "addUserToGroup").resolves({ conflict: true });
sinon.stub(awsFunctions, "fetchAwsUserIdByUsername").resolves("existing-user-id-123");

const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '12345'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(200);
expect(res.body).to.have.property('message',
'User 12345 is already part of the AWS group, please try signing in.'
);
return done();
});
});
});
Loading
Loading