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 0.0.1 to 1.0.2

prettier.config.js

289

lib/index.js

@@ -8,3 +8,3 @@ const Superagent = require('superagent');

}
};
}

@@ -14,3 +14,3 @@ function validateReturnTo(ctx) {

const validReturnTo = (ctx.configuration.fusebit_allowed_return_to || '').split(',');
const match = validReturnTo.find(allowed => {
const match = validReturnTo.find((allowed) => {
if (allowed === ctx.query.returnTo) {

@@ -25,7 +25,5 @@ return true;

if (!match) {
throw {
status: 403,
message: `The specified 'returnTo' URL '${ctx.query.returnTo}' does not match any of the allowed returnTo URLs of the '${
ctx.boundaryId}/${ctx.functionId}' Fusebit Add-On component. If this is a valid request, add the specified 'returnTo' URL to the 'fusebit_allowed_return_to' configuration property of the '${
ctx.boundaryId}/${ctx.functionId}' Fusebit Add-On component.`
throw {
status: 403,
message: `The specified 'returnTo' URL '${ctx.query.returnTo}' does not match any of the allowed returnTo URLs of the '${ctx.boundaryId}/${ctx.functionId}' Fusebit Add-On component. If this is a valid request, add the specified 'returnTo' URL to the 'fusebit_allowed_return_to' configuration property of the '${ctx.boundaryId}/${ctx.functionId}' Fusebit Add-On component.`,
};

@@ -40,3 +38,3 @@ }

const { states, initialState } = configure;
return async (ctx) => {
return async (ctx) => {
if (!disableDebug) {

@@ -53,3 +51,3 @@ debug('DEBUGGING ENABLED. To disable debugging information, comment out the `debug` configuration setting.');

if (ctx.query.status === 'error') {
// This is a callback from a subordinate service that resulted in an error; propagate
// This is a callback from a subordinate service that resulted in an error; propagate
throw { status: data.status || 500, message: data.message || 'Unspecified error', state };

@@ -60,11 +58,9 @@ }

return await stateHandler(ctx, state, data);
}
else {
} else {
throw { status: 400, message: `Unsupported configuration state '${state.configurationState}'`, state };
}
}
catch (e) {
} catch (e) {
return exports.completeWithError(ctx, e);
}
}
};
};

@@ -79,4 +75,4 @@

let lastSegment;
do {
lastSegment = pathSegments.pop();
do {
lastSegment = pathSegments.pop();
} while (!lastSegment && pathSegments.length > 0);

@@ -91,7 +87,6 @@ try {

return await settingsManager(ctx);
}
else {
} else {
// There is no configuration stage, simply redirect back to the caller with success
validateReturnTo(ctx);
let [state, data] = exports.getInputs(ctx, configure && configure.initialState || 'none');
let [state, data] = exports.getInputs(ctx, (configure && configure.initialState) || 'none');
return exports.completeWithSuccess(state, data);

@@ -112,9 +107,8 @@ }

throw { status: 404, message: 'Not found' };
};
}
catch (e) {
}
} catch (e) {
return exports.completeWithError(ctx, e);
}
};
}
};

@@ -129,4 +123,3 @@ exports.serializeState = (state) => Buffer.from(JSON.stringify(state)).toString('base64');

data = ctx.query.data ? exports.deserializeState(ctx.query.data) : {};
}
catch (e) {
} catch (e) {
throw { status: 400, message: `Malformed 'data' parameter` };

@@ -137,5 +130,8 @@ }

if (!initialConfigurationState) {
throw { status: 400, message: `State consistency error. Initial configuration state is not specified, and 'state' parameter is missing.` };
throw {
status: 400,
message: `State consistency error. Initial configuration state is not specified, and 'state' parameter is missing.`,
};
}
['baseUrl', 'accountId', 'subscriptionId', 'boundaryId','functionId', 'templateName'].forEach(p => {
['baseUrl', 'accountId', 'subscriptionId', 'boundaryId', 'functionId', 'templateName'].forEach((p) => {
if (!data[p]) {

@@ -145,10 +141,15 @@ throw { status: 400, message: `Missing 'data.${p}' input parameter`, state: ctx.query.state };

});
return [{ configurationState: initialConfigurationState, returnTo: ctx.query.returnTo, returnToState: ctx.query.state}, data];
}
else if (ctx.query.state) {
return [
{
configurationState: initialConfigurationState,
returnTo: ctx.query.returnTo,
returnToState: ctx.query.state,
},
data,
];
} else if (ctx.query.state) {
// Continuation of the add-on component interaction (e.g. form post from a settings manager)
try {
return [JSON.parse(Buffer.from(ctx.query.state, 'base64').toString()), data];
}
catch (e) {
} catch (e) {
throw { status: 400, message: `Malformed 'state' parameter` };

@@ -159,9 +160,9 @@ }

}
}
};
exports.completeWithSuccess = (state, data) => {
const location = `${state.returnTo}?status=success&data=${
encodeURIComponent(exports.serializeState(data))
}` + (state.returnToState ? `&state=${encodeURIComponent(state.returnToState)}` : '');
return { status: 302, headers: { location }};
const location =
`${state.returnTo}?status=success&data=${encodeURIComponent(exports.serializeState(data))}` +
(state.returnToState ? `&state=${encodeURIComponent(state.returnToState)}` : '');
return { status: 302, headers: { location } };
};

@@ -171,12 +172,11 @@

debug('COMPLETE WITH ERROR', error);
let returnTo = error.state && error.state.returnTo || ctx.query.returnTo;
let state = error.state && error.state.returnToState || (ctx.query.returnTo && ctx.query.state);
let returnTo = (error.state && error.state.returnTo) || ctx.query.returnTo;
let state = (error.state && error.state.returnToState) || (ctx.query.returnTo && ctx.query.state);
let body = { status: error.status || 500, message: error.message };
if (returnTo) {
const location = `${returnTo}?status=error&data=${
encodeURIComponent(exports.serializeState(body))
}` + (state ? `&state=${encodeURIComponent(state)}` : '');
return { status: 302, headers: { location }};
}
else {
const location =
`${returnTo}?status=error&data=${encodeURIComponent(exports.serializeState(body))}` +
(state ? `&state=${encodeURIComponent(state)}` : '');
return { status: 302, headers: { location } };
} else {
return { status: body.status, body };

@@ -187,54 +187,157 @@ }

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}`;
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}`;
};
exports.redirect = (ctx, state, data, redirectUrl, nextConfigurationState) => {
state.configurationState = nextConfigurationState;
const location = `${
redirectUrl
}?returnTo=${
`${exports.getSelfUrl(ctx)}/configure`
}&state=${
encodeURIComponent(exports.serializeState(state))
}&data=${
encodeURIComponent(exports.serializeState(data))
}`;
const location = `${redirectUrl}?returnTo=${`${exports.getSelfUrl(ctx)}/configure`}&state=${encodeURIComponent(
exports.serializeState(state)
)}&data=${encodeURIComponent(exports.serializeState(data))}`;
return { status: 302, headers: { location } };
}
};
exports.createStorage = async (ctx) => {
let issuerCreated = false;
let issuerId;
let clientId;
try {
// Create a PKI issuer to represent the the Add-on Handler
issuerId = `uri:fusebit-template:addon-${ctx.body.functionId}:${ctx.body.subscriptionId}:${ctx.body.boundaryId}:${ctx.body.functionId}`;
console.log(`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 }))
)
);
console.log('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 add-on handler ${ctx.body.subscriptionId}/${ctx.body.boundaryId}/${ctx.body.functionId}`,
publicKeys: [{ keyId, publicKey }],
});
issuerCreated = true;
console.log('ISSUER CREATED');
// Create a Client for the add-on handler with permissions to storage
const subject = 'client-1';
const storageId = uuid.v4();
console.log(`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 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;
console.log('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;
}
};
exports.createFunction = async (ctx, functionSpecification) => {
let functionCreated = false;
try {
let url = `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${
ctx.body.subscriptionId
}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}`;
// Acquire any additional configuration elements from optional components
let additionalCfg = {};
// Is storage requested?
if (functionSpecification.enableStorage) {
delete functionSpecification.enableStorage;
additionalCfg = exports.createStorage(additionalCfg);
if (typeof functionSpecification.nodejs.files['package.json'] === 'object') {
functionSpecification.nodejs.files['package.json'].dependencies['@fusebit/add-on-sdk'] = '*';
} else if (typeof functionSpecification.nodejs.files['package.json'] === 'string') {
let pkg = JSON.parse(functionSpecification.nodejs.files['package.json']);
pkg.dependencies['@fusebit/add-on-sdk'] = '*';
functionSpecification.nodejs.files['package.json'] = pkg;
}
}
// Add the additional configuration elements to the specification
if (functionSpecification.configurationSerialized) {
functionSpecification.configurationSerialized += `# Storage configuration settings
${Object.keys(additionalCfg)
.sort()
.map((k) => `${k}=${ctx.body.configuration[k]}`)
.join('\n')}
`;
} else {
functionSpecification.configuration = { ...functionSpecification.configuration, ...additionalCfg };
}
// 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
.set('Authorization', ctx.headers['authorization']) // pass-through authorization
.send(functionSpecification);
functionCreated = true;
// Wait for the function to be built and ready
let attempts = 15;
while (response.status === 201 && attempts > 0) {
response = await Superagent.get(
`${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']);
`${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']);
if (response.status === 200) {
if (response.body.status === "success") {
if (response.body.status === 'success') {
return;
} else {
throw new Error(
`Failure creating function: ${(response.body.error &&
response.body.error.message) ||
"Unknown error"}`
`Failure creating function: ${(response.body.error && response.body.error.message) || 'Unknown error'}`
);
}
}
await new Promise(resolve => setTimeout(resolve, 2000));
await new Promise((resolve) => setTimeout(resolve, 2000));
attempts--;

@@ -245,3 +348,4 @@ }

}
if (response.status === 204 || (response.body && response.body.status === "success")) {
if (response.status === 204 || (response.body && response.body.status === 'success')) {
return;

@@ -251,4 +355,3 @@ } else {

}
}
catch (e) {
} catch (e) {
if (functionCreated) {

@@ -265,6 +368,32 @@ try {

await Superagent.delete(
`${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
`${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
};
exports.getStorageClient = (ctx) => {
const accessToken = Jwt.sign({}, Buffer.from(ctx.configuration.fusebit_storage_key, 'base64').toString('utf8'), {
algorithm: 'RS256',
expiresIn: 60 * 60 * 24,
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 url = `${ctx.configuration.fusebit_storage_audience}/v1/account/${ctx.configuration.fusebit_storage_account_id}/subscription/${ctx.configuration.fusebit_storage_subscription_id}/storage/${ctx.configuration.fusebit_storage_id}`;
return {
get: async () => {
const response = await Superagent.get(url)
.set('Authorization', `Bearer ${accessToken}`)
.ok((res) => res.status < 300 || res.status === 404);
return response.status === 404 ? undefined : response.body.data;
},
put: async (data) => {
await Superagent.put(url).set('Authorization', `Bearer ${accessToken}`).send({ data });
},
};
};
{
"name": "@fusebit/add-on-sdk",
"version": "0.0.1",
"version": "1.0.2",
"description": "SDK for implementing Fusebit Add-Ons",

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

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