Public
Edited
Mar 23, 2024
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
suite.test("Can use the AWS API based on user supplied password", () => {
expect(testAWSAPICallResponse.Body.toString()).toBe("foo")
})
Insert cell
Insert cell
encode = async (password, salt) => (await argon2.hash({
pass: password,
salt: salt,
time: 10, // rounds
mem: 1024, // used memory, in KiB
type: argon2.ArgonType.Argon2i // OWASP recommendation
})).hashHex;
Insert cell
Insert cell
Insert cell
credential_generator = async (req, res, context) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, authorization");
res.header("Access-Control-Allow-Methods", "GET, OPTIONS");
if (req.method === 'OPTIONS') res.status(200).end(); // Get CORS preflights ACKed ASAP
// Password check
if (await encode(req.headers['authorization'], salt) !== stored_password) {
res.status(403).end()
}
// Fetch master AWS secrets from secret store. In the form "<CLIENT>,<SECRET>"
const aws_creds = context.secrets['tomlarkworthy_aws'].split(",");
AWS.config.credentials = new AWS.ChainableTemporaryCredentials({
masterCredentials: {
accessKeyId: aws_creds[0],
secretAccessKey: aws_creds[1]
}
});
// Request a fresh token and return derived temporary credentials
await AWS.config.credentials.refreshPromise()
res.json({
accessKeyId: AWS.config.credentials.accessKeyId,
secretAccessKey: AWS.config.credentials.secretAccessKey,
sessionToken: AWS.config.credentials.sessionToken
});
}
Insert cell
Insert cell
Insert cell
credentials = deploy("credentials", credential_generator, {
secrets: ["tomlarkworthy_aws"] // Here is how master creds are injected
})
Insert cell
Insert cell
Insert cell
CredFetcher = class CredFetcher extends AWS.Credentials {
constructor() {
super();
this.expired = true;
}
needsRefresh() {
return this.expired || Date() - this.lastRefresh > 15 * 60 * 1000; // Refresh every 15 mins
}
refresh(callback) {
const self = this;
fetch(credentials.href, {
headers: { authorization: password } // User supplied password
})
.then((r) => r.json())
.then((creds) => {
this.accessKeyId = creds.accessKeyId;
this.secretAccessKey = creds.secretAccessKey;
this.sessionToken = creds.sessionToken;
this.lastRefresh = Date();
this.expired = false;
callback();
})
.catch((err) => callback(err));
}
}
Insert cell
assign_creds = {
AWS.config.credentials = new CredFetcher();
}
Insert cell
Insert cell
Insert cell
testAWSAPICallResponse = {
assign_creds; // Make sure we retry after loading creds
return new AWS.S3()
.getObject({
Bucket: "tomlarkworthy-access-aws",
Key: "access-aws/example.txt"
})
.promise();
}
Insert cell
suite.test("00: GetObject returns file containing 'foo'", () => {
expect(testAWSAPICallResponse.Body.toString()).toBe("foo")
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { footer } from "@tomlarkworthy/footer"
Insert cell
footer
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more