New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@fusebit/add-on-sdk

Package Overview
Dependencies
Maintainers
3
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fusebit/add-on-sdk - npm Package Compare versions

Comparing version 2.1.0 to 3.0.0

254

lib/index.js
const Superagent = require('superagent');
const Url = require('url');
const Jwt = require('jsonwebtoken');
const uuid = require('uuid');

@@ -175,6 +173,3 @@ function debug() {

exports.getSelfUrl = (ctx) => {
const baseUrl = ctx.headers['x-forwarded-proto']
? `${ctx.headers['x-forwarded-proto'].split(',')[0]}://${ctx.headers.host}`
: `${ctx.protocol}://${ctx.headers.host}`;
return `${baseUrl}/v1/run/${ctx.subscriptionId}/${ctx.boundaryId}/${ctx.functionId}`;
return ctx.baseUrl;
};

@@ -192,148 +187,9 @@

function generateIssuerSubject(ctx) {
return {
issuerId: `uri:fusebit-template:${ctx.functionId}:${ctx.body.subscriptionId}:${ctx.body.boundaryId}:${ctx.body.functionId}`,
subject: 'client-1',
};
}
exports.createStorage = async (ctx) => {
let issuerCreated = false;
let { issuerId, subject } = generateIssuerSubject(ctx);
let clientId;
try {
// Create a PKI issuer to represent the the Add-on Handler
debug(`Creating the storage keys: ${issuerId}`);
const keyId = 'key-1';
const { publicKey, privateKey } = await new Promise((resolve, reject) =>
require('crypto').generateKeyPair(
'rsa',
{
modulusLength: 512,
publicKeyEncoding: { format: 'pem', type: 'spki' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
},
(error, publicKey, privateKey) => (error ? reject(error) : resolve({ publicKey, privateKey }))
)
);
debug('Creating the issuer');
await Superagent.post(`${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/issuer/${encodeURIComponent(issuerId)}`)
.set('Authorization', ctx.headers['authorization']) // pass-through authorization
.send({
displayName: `Issuer for ${ctx.functionId} add-on handler ${ctx.body.subscriptionId}/${ctx.body.boundaryId}/${ctx.body.functionId}`,
publicKeys: [{ keyId, publicKey }],
});
issuerCreated = true;
debug('ISSUER CREATED');
// Create a Client for the add-on handler with permissions to storage
const storageId = uuid.v4();
debug(`Creating the storage client: ${storageId}`);
clientId = (
await Superagent.post(`${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/client`)
.set('Authorization', ctx.headers['authorization']) // pass-through authorization
.send({
displayName: `Client for ${ctx.functionId} add-on handler ${ctx.body.subscriptionId}/${ctx.body.boundaryId}/${ctx.body.functionId}`,
identities: [{ issuerId, subject }],
access: {
allow: [
{
action: 'storage:*',
resource: `/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/storage/${storageId}/`,
},
],
},
})
).body.id;
debug('Storage successfully created');
// Return the appropriate configuration elements for a consumer.
return {
fusebit_storage_key: Buffer.from(privateKey).toString('base64'),
fusebit_storage_key_id: keyId,
fusebit_storage_issuer_id: issuerId,
fusebit_storage_subject: subject,
fusebit_storage_id: storageId,
fusebit_storage_audience: ctx.body.baseUrl,
fusebit_storage_account_id: ctx.body.accountId,
fusebit_storage_subscription_id: ctx.body.subscriptionId,
};
} catch (e) {
if (clientId) {
try {
await Superagent.delete(`${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/client/${clientId}`).set(
'Authorization',
ctx.headers['authorization']
); // pass-through authorization
} catch (_) {}
}
if (issuerCreated) {
try {
await Superagent.delete(`${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/issuer/${encodeURIComponent(issuerId)}`).set(
'Authorization',
ctx.headers['authorization']
); // pass-through authorization
} catch (_) {}
}
throw e;
}
};
function generateStorageUrl(storageCtx) {
return `${storageCtx.fusebit_storage_audience}/v1/account/${storageCtx.fusebit_storage_account_id}/subscription/${storageCtx.fusebit_storage_subscription_id}/storage/${storageCtx.fusebit_storage_id}`;
}
exports.deleteStorage = async (ctx, storageCtx) => {
debug('DELETE STORAGE');
const issuerId = storageCtx.fusebit_storage_issuer_id;
const subject = storageCtx.fusebit_storage_subject;
const accountId = storageCtx.fusebit_storage_account_id;
if (!issuerId || !subject || !accountId) {
debug('Storage not configured for this function');
return;
}
// Delete the storage
debug('Deleting storage');
await Superagent.delete(generateStorageUrl(storageCtx))
.set('Authorization', ctx.headers['authorization']) // pass-through authorization
.ok((r) => r.status < 300 || r.status === 404);
debug('Deleted storage');
// Find the client
debug('Looking up Client ID', issuerId);
const response = await Superagent.get(
`${ctx.body.baseUrl}/v1/account/${accountId}/client?issuerId=${encodeURIComponent(issuerId)}&subject=${subject}&include=all`
).set('Authorization', ctx.headers['authorization']); // pass-through authorization
const client = response.body.items && response.body.items[0];
debug('Found client', client);
if (client) {
// Delete the client
debug('Deleting client');
await Superagent.delete(`${ctx.body.baseUrl}/v1/account/${accountId}/client/${client.id}`)
.set('Authorization', ctx.headers['authorization']) // pass-through authorization
.ok((r) => r.status < 300 || r.status === 404);
debug('Deleted client');
}
// Delete the issuer
debug('Deleting issuer', issuerId);
await Superagent.delete(`${ctx.body.baseUrl}/v1/account/${accountId}/issuer/${encodeURIComponent(issuerId)}`)
.set('Authorization', ctx.headers['authorization']) // pass-through authorization
.ok((r) => r.status < 300 || r.status === 404);
debug('Deleted issuer');
};
exports.createFunction = async (ctx, functionSpecification) => {
exports.createFunction = async (ctx, functionSpecification, accessToken) => {
let functionCreated = false;
const accessTokenHeader = `Bearer ${accessToken}`;
try {
// Create the function
let url = `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}`;
let response = await Superagent.put(url)
.set('Authorization', ctx.headers['authorization']) // pass-through authorization
.send(functionSpecification);
let response = await Superagent.put(url).set('Authorization', accessTokenHeader).send(functionSpecification);
functionCreated = true;

@@ -346,6 +202,6 @@

`${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}/build/${response.body.buildId}`
).set('Authorization', ctx.headers['authorization']);
).set('Authorization', accessTokenHeader);
if (response.status === 200) {
if (response.body.status === 'success') {
return;
break;
} else {

@@ -365,10 +221,18 @@ throw new Error(

if (response.status === 204 || (response.body && response.body.status === 'success')) {
return;
} else {
throw response.body;
if (response.body && response.body.location) {
return response.body.location;
} else {
response = await Superagent.get(
`${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}/location`
).set('Authorization', accessTokenHeader);
if (response.body && response.body.location) {
return response.body.location;
}
}
}
throw response.body;
} catch (e) {
if (functionCreated) {
try {
await exports.deleteFunction(ctx);
await exports.deleteFunction(ctx, accessToken);
} catch (_) {}

@@ -380,3 +244,3 @@ }

exports.deleteFunction = async (ctx, boundaryId, functionId) => {
exports.deleteFunction = async (ctx, accessToken, boundaryId, functionId) => {
await Superagent.delete(

@@ -386,11 +250,13 @@ `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${

}/function/${functionId || ctx.body.functionId}`
).set('Authorization', ctx.headers['authorization']); // pass-through authorization
)
.set('Authorization', `Bearer ${accessToken}`)
.ok((res) => res.status === 204 || res.status === 404);
};
exports.getFunctionDefinition = async (ctx, boundaryId, functionId) => {
let response = await Superagent.get(
exports.getFunctionDefinition = async (ctx, accessToken, boundaryId, functionId) => {
const response = await Superagent.get(
`${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${
boundaryId || ctx.body.boundaryId
}/function/${functionId || ctx.body.functionId}`
).set('Authorization', ctx.headers['authorization']); // pass-through authorization
).set('Authorization', `Bearer ${accessToken}`);

@@ -400,8 +266,8 @@ return response.body;

exports.getFunctionUrl = async (ctx, boundaryId, functionId) => {
let response = await Superagent.get(
exports.getFunctionUrl = async (ctx, accessToken, boundaryId, functionId) => {
const response = await Superagent.get(
`${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${
boundaryId || ctx.body.boundaryId
}/function/${functionId || ctx.body.functionId}/location`
).set('Authorization', ctx.headers['authorization']); // pass-through authorization
).set('Authorization', `Bearer ${accessToken}`);

@@ -411,36 +277,48 @@ return response.body.location;

exports.getStorageClient = (ctx) => {
const expiry = 60 * 16; // 15+1 min to align with Lambda lifecycle plus some buffer
const accessToken = Jwt.sign({}, Buffer.from(ctx.configuration.fusebit_storage_key, 'base64').toString('utf8'), {
algorithm: 'RS256',
expiresIn: expiry,
audience: ctx.configuration.fusebit_storage_audience,
issuer: ctx.configuration.fusebit_storage_issuer_id,
subject: ctx.configuration.fusebit_storage_subject,
keyid: ctx.configuration.fusebit_storage_key_id,
header: { jwtId: Date.now().toString() },
});
const removeLeadingSlash = (s) => s.replace(/^\/(.+)$/, '$1');
const removeTrailingSlash = (s) => s.replace(/^(.+)\/$/, '$1');
const url = generateStorageUrl(ctx.configuration);
exports.createStorageClient = async (ctx, accessToken, storageIdPrefix) => {
storageIdPrefix = storageIdPrefix ? removeLeadingSlash(removeTrailingSlash(storageIdPrefix)) : '';
const functionUrl = Url.parse(ctx.baseUrl);
let storageBaseUrl = `${functionUrl.protocol}//${functionUrl.host}/v1/account/${ctx.accountId}/subscription/${
ctx.subscriptionId
}/storage${storageIdPrefix ? '/' + storageIdPrefix : ''}`;
return {
etag: null,
expiration: Date.now() + expiry * 1000,
get: async function () {
const response = await Superagent.get(url)
const getUrl = (storageSubId) => {
storageSubId = storageSubId ? removeTrailingSlash(removeLeadingSlash(storageSubId)) : '';
return `${storageBaseUrl}${storageSubId ? '/' + storageSubId : ''}`;
};
const storageClient = {
get: async function (storageSubId) {
const response = await Superagent.get(getUrl(storageSubId))
.set('Authorization', `Bearer ${accessToken}`)
.ok((res) => res.status < 300 || res.status === 404);
this.etag = response.body.etag;
return response.status === 404 ? undefined : response.body.data;
return response.status === 404 ? undefined : response.body;
},
put: async function (data, force) {
let request = Superagent.put(url).set('Authorization', `Bearer ${accessToken}`);
let payload = { data: data };
if (!force) {
payload.etag = this.etag;
put: async function (data, storageSubId) {
const response = await Superagent.put(getUrl(storageSubId)).set('Authorization', `Bearer ${accessToken}`).send(data);
return response.body;
},
delete: async function (storageSubId, recursive, forceRecursive) {
storageSubId = storageSubId ? removeLeadingSlash(removeTrailingSlash(storageSubId)) : '';
if (!storageSubId && !storageIdPrefix && recursive && !forceRecursive) {
throw new Error(
'You are attempting to recursively delete all storage objects in the Fusebit subscription. If this is your intent, please pass "true" as the third parameter in the call to delete(storageSubId, recursive, forceRecursive).'
);
}
const response = await request.send(payload);
this.etag = response.body.etag;
await Superagent.delete(`${getUrl(storageSubId)}${recursive ? '/*' : ''}`).set('Authorization', `Bearer ${accessToken}`);
return;
},
list: async function (storageSubId, { count, next }) {
const response = await Superagent.get(`${getUrl(storageSubId)}/*`)
.query(isNaN(count) ? undefined : { count })
.query(typeof next === 'string' ? { next } : undefined)
.set('Authorization', `Bearer ${accessToken}`);
return response.body;
},
};
return storageClient;
};
{
"name": "@fusebit/add-on-sdk",
"version": "2.1.0",
"version": "3.0.0",
"description": "SDK for implementing Fusebit Add-Ons",

@@ -11,5 +11,3 @@ "main": "lib/index.js",

"dependencies": {
"jsonwebtoken": "^8.5.1",
"superagent": "^5.2.2",
"uuid": "^8.2.0"
"superagent": "^6.1.0"
},

@@ -16,0 +14,0 @@ "devDependencies": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc