Milestone 0: import zappier billing, Verae middleware, and Zapier research
Compose-ready workspace: packages/zappier (rate card, portal, Stripe), packages/verae-zapier-middleware (timestamp + NATS), packages/verae-zapier (CLI app), vendor/zapier-platform, and research/zapier vendor corpus. Gate 0 structure checks pass. Product code and research are not yet wired.
This commit is contained in:
commit
b4150c8250
1364 changed files with 6814366 additions and 0 deletions
1227
vendor/zapier-platform/packages/legacy-scripting-runner/test/bundle.js
vendored
Normal file
1227
vendor/zapier-platform/packages/legacy-scripting-runner/test/bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
11
vendor/zapier-platform/packages/legacy-scripting-runner/test/constants.js
vendored
Normal file
11
vendor/zapier-platform/packages/legacy-scripting-runner/test/constants.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
const AUTH_JSON_SERVER_URL =
|
||||
process.env.AUTH_JSON_SERVER_URL ||
|
||||
'https://auth-json-server.zapier-staging.com';
|
||||
|
||||
const HTTPBIN_URL =
|
||||
process.env.HTTPBIN_URL || 'https://httpbin.zapier-tooling.com';
|
||||
|
||||
module.exports = {
|
||||
AUTH_JSON_SERVER_URL,
|
||||
HTTPBIN_URL,
|
||||
};
|
||||
35
vendor/zapier-platform/packages/legacy-scripting-runner/test/example-app/api-key-auth.js
vendored
Normal file
35
vendor/zapier-platform/packages/legacy-scripting-runner/test/example-app/api-key-auth.js
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
const { AUTH_JSON_SERVER_URL } = require('../constants');
|
||||
|
||||
const testAuthSource = `
|
||||
const responsePromise = z.request({
|
||||
url: '${AUTH_JSON_SERVER_URL}/me'
|
||||
});
|
||||
return responsePromise.then(response => {
|
||||
if (response.status !== 200) {
|
||||
throw new Error('Auth failed');
|
||||
}
|
||||
return z.JSON.parse(response.content);
|
||||
});
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
legacy: {
|
||||
authentication: {
|
||||
mapping: { 'X-Api-Key': '{{api_key}}' },
|
||||
placement: 'header',
|
||||
},
|
||||
},
|
||||
|
||||
authentication: {
|
||||
type: 'custom',
|
||||
test: { source: testAuthSource },
|
||||
fields: [
|
||||
{
|
||||
key: 'api_key',
|
||||
label: 'API Key',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
1509
vendor/zapier-platform/packages/legacy-scripting-runner/test/example-app/index.js
vendored
Normal file
1509
vendor/zapier-platform/packages/legacy-scripting-runner/test/example-app/index.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
60
vendor/zapier-platform/packages/legacy-scripting-runner/test/example-app/oauth2.js
vendored
Normal file
60
vendor/zapier-platform/packages/legacy-scripting-runner/test/example-app/oauth2.js
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
const { AUTH_JSON_SERVER_URL } = require('../constants');
|
||||
|
||||
const testAuthSource = `
|
||||
const responsePromise = z.request({
|
||||
url: '${AUTH_JSON_SERVER_URL}/me'
|
||||
});
|
||||
return responsePromise.then(response => {
|
||||
if (response.status !== 200) {
|
||||
throw new Error('Auth failed');
|
||||
}
|
||||
return z.JSON.parse(response.content);
|
||||
});
|
||||
`;
|
||||
|
||||
const getAuthorizeUrlSource = `
|
||||
return z.legacyScripting.run(bundle, 'auth.oauth2.authorize');
|
||||
`;
|
||||
|
||||
const getAccessTokenSource = `
|
||||
return z.legacyScripting.run(bundle, 'auth.oauth2.token');
|
||||
`;
|
||||
|
||||
const refreshAccessTokenSource = `
|
||||
return z.legacyScripting.run(bundle, 'auth.oauth2.refresh');
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
legacy: {
|
||||
authentication: {
|
||||
placement: 'header',
|
||||
mapping: {},
|
||||
},
|
||||
},
|
||||
authentication: {
|
||||
type: 'oauth2',
|
||||
test: { source: testAuthSource },
|
||||
fields: [
|
||||
// No need to define access_token and refresh_token here, they will be
|
||||
// added automatically by the backend
|
||||
{
|
||||
key: 'something_custom',
|
||||
type: 'string',
|
||||
required: true,
|
||||
computed: true,
|
||||
},
|
||||
],
|
||||
oauth2Config: {
|
||||
authorizeUrl: {
|
||||
source: getAuthorizeUrlSource,
|
||||
},
|
||||
getAccessToken: {
|
||||
source: getAccessTokenSource,
|
||||
},
|
||||
refreshAccessToken: {
|
||||
source: refreshAccessTokenSource,
|
||||
},
|
||||
autoRefresh: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
47
vendor/zapier-platform/packages/legacy-scripting-runner/test/example-app/session-auth.js
vendored
Normal file
47
vendor/zapier-platform/packages/legacy-scripting-runner/test/example-app/session-auth.js
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
'use strict';
|
||||
|
||||
const testAuthSource = `
|
||||
return z.legacyScripting.run(bundle, 'trigger', 'contact_full');
|
||||
`;
|
||||
|
||||
const getSessionKeySource = `
|
||||
return z.legacyScripting.run(bundle, 'auth.session');
|
||||
`;
|
||||
|
||||
const getConnectionLabelSource = `
|
||||
return z.legacyScripting.run(bundle, 'auth.connectionLabel');
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
legacy: {
|
||||
authentication: {
|
||||
mapping: {
|
||||
'X-Api-Key': '{{key1}}{{key2}}',
|
||||
},
|
||||
placement: 'header',
|
||||
},
|
||||
testTrigger: 'contact_full',
|
||||
},
|
||||
authentication: {
|
||||
type: 'session',
|
||||
test: { source: testAuthSource },
|
||||
fields: [
|
||||
{
|
||||
key: 'username',
|
||||
label: 'Username',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
key: 'password',
|
||||
label: 'Password',
|
||||
type: 'password',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
sessionConfig: {
|
||||
perform: { source: getSessionKeySource },
|
||||
},
|
||||
connectionLabel: { source: getConnectionLabelSource },
|
||||
},
|
||||
};
|
||||
4939
vendor/zapier-platform/packages/legacy-scripting-runner/test/integration-test.js
vendored
Normal file
4939
vendor/zapier-platform/packages/legacy-scripting-runner/test/integration-test.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
34
vendor/zapier-platform/packages/legacy-scripting-runner/test/libraries.js
vendored
Normal file
34
vendor/zapier-platform/packages/legacy-scripting-runner/test/libraries.js
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
require('should');
|
||||
|
||||
describe('Utils/Libraries', () => {
|
||||
it('btoa', (done) => {
|
||||
const btoa = require('../btoa');
|
||||
const result = btoa('something');
|
||||
result.should.equal('c29tZXRoaW5n');
|
||||
done();
|
||||
});
|
||||
|
||||
it('atob', (done) => {
|
||||
const atob = require('../atob');
|
||||
const result = atob('c29tZXRoaW5n');
|
||||
result.should.equal('something');
|
||||
done();
|
||||
});
|
||||
|
||||
describe('$', () => {
|
||||
const $ = require('../$');
|
||||
|
||||
it('$.param()', (done) => {
|
||||
const result = $.param({ test: 'something', more: true, also: '@' });
|
||||
result.should.equal('test=something&more=true&also=%40');
|
||||
done();
|
||||
});
|
||||
|
||||
it('$.parseXML()', (done) => {
|
||||
const xml = $.parseXML('<do><something>also</something></do>');
|
||||
const result = xml.getElementsByTagName('do').length;
|
||||
result.should.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
88
vendor/zapier-platform/packages/legacy-scripting-runner/test/runner.js
vendored
Normal file
88
vendor/zapier-platform/packages/legacy-scripting-runner/test/runner.js
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
const should = require('should');
|
||||
|
||||
const scriptingRunner = require('../index');
|
||||
|
||||
describe('scriptingRunner', () => {
|
||||
const defaultBundle = {
|
||||
_legacyUrl: 'https://zapier.com',
|
||||
inputData: {
|
||||
user: 'Zapier',
|
||||
},
|
||||
authData: {
|
||||
apiKey: 'Zapier-API-Key',
|
||||
},
|
||||
meta: {
|
||||
frontend: false,
|
||||
prefill: false,
|
||||
},
|
||||
};
|
||||
|
||||
const z = {
|
||||
request: () => {},
|
||||
};
|
||||
|
||||
it('should return nothing if there is no scripting', (done) => {
|
||||
const event = {
|
||||
name: 'trigger.poll',
|
||||
key: 'trigger',
|
||||
response: {
|
||||
status: 200,
|
||||
content: '[{"id": 1, "name": "Zapier"}]',
|
||||
},
|
||||
};
|
||||
const bundle = defaultBundle;
|
||||
const Zap = {};
|
||||
|
||||
const legacyScriptingRunner = scriptingRunner(Zap);
|
||||
|
||||
legacyScriptingRunner
|
||||
.runEvent(event, z, bundle)
|
||||
.then((result) => {
|
||||
should(result).eql(undefined);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should return nothing if there is no event', (done) => {
|
||||
const event = {};
|
||||
const bundle = defaultBundle;
|
||||
const Zap = {
|
||||
trigger_poll: () => true,
|
||||
};
|
||||
|
||||
const legacyScriptingRunner = scriptingRunner(Zap);
|
||||
|
||||
legacyScriptingRunner
|
||||
.runEvent(event, z, bundle)
|
||||
.then((result) => {
|
||||
should(result).eql(undefined);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
it('should return nothing if there is no event.name', (done) => {
|
||||
const event = {
|
||||
key: 'trigger',
|
||||
response: {
|
||||
status: 200,
|
||||
content: '[{"id": 1, "name": "Zapier"}]',
|
||||
},
|
||||
};
|
||||
const bundle = defaultBundle;
|
||||
const Zap = {
|
||||
trigger_poll: () => true,
|
||||
};
|
||||
|
||||
const legacyScriptingRunner = scriptingRunner(Zap);
|
||||
|
||||
legacyScriptingRunner
|
||||
.runEvent(event, z, bundle)
|
||||
.then((result) => {
|
||||
should(result).eql(undefined);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
59
vendor/zapier-platform/packages/legacy-scripting-runner/test/template-security.js
vendored
Normal file
59
vendor/zapier-platform/packages/legacy-scripting-runner/test/template-security.js
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
const { renderTemplate } = require('../middleware-factory');
|
||||
|
||||
describe('middleware renderTemplate security', () => {
|
||||
it('should handle normal template rendering', () => {
|
||||
const context = { clientId: 'test123', secret: 'mysecret' };
|
||||
const template = 'Client: {{clientId}}, Secret: {{secret}}';
|
||||
|
||||
const result = renderTemplate(template, context);
|
||||
result.should.equal('Client: test123, Secret: mysecret');
|
||||
});
|
||||
|
||||
it('should prevent code injection in middleware templates', () => {
|
||||
const context = {
|
||||
clientId: 'test123',
|
||||
malicious: 'process.exit(1)',
|
||||
};
|
||||
|
||||
// This should NOT execute the malicious code
|
||||
const result = renderTemplate(
|
||||
'ID: {{clientId}}, Value: {{malicious}}',
|
||||
context,
|
||||
);
|
||||
result.should.equal('ID: test123, Value: process.exit(1)');
|
||||
});
|
||||
|
||||
it('should handle non-string template input safely in middleware', () => {
|
||||
const context = { test: 'value' };
|
||||
|
||||
(() => {
|
||||
renderTemplate({}, context);
|
||||
}).should.throw('Template string must be a primitive');
|
||||
|
||||
(() => {
|
||||
renderTemplate([], context);
|
||||
}).should.throw('Template string must be a primitive');
|
||||
|
||||
(() => {
|
||||
renderTemplate(() => {
|
||||
console.log('do evil stuff');
|
||||
}, context);
|
||||
}).should.throw('Template string must be a primitive');
|
||||
});
|
||||
|
||||
it('should handle template errors gracefully in middleware', () => {
|
||||
const context = { name: 'John' };
|
||||
|
||||
// Malformed template should return original string, not crash
|
||||
const result = renderTemplate('{{unclosed', context);
|
||||
result.should.equal('{{unclosed');
|
||||
});
|
||||
|
||||
it('should handle undefined variables with defaults', () => {
|
||||
const context = { name: 'John' };
|
||||
|
||||
// renderTemplate sets undefined vars to empty string
|
||||
const result = renderTemplate('{{name}} {{undefined_var}}', context);
|
||||
result.should.equal('John ');
|
||||
});
|
||||
});
|
||||
122
vendor/zapier-platform/packages/legacy-scripting-runner/test/zfactory.js
vendored
Normal file
122
vendor/zapier-platform/packages/legacy-scripting-runner/test/zfactory.js
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
const should = require('should');
|
||||
|
||||
const z = require('../zfactory')();
|
||||
const { HTTPBIN_URL } = require('./constants');
|
||||
|
||||
describe('z', () => {
|
||||
it('z.hash', (done) => {
|
||||
const result = z.hash('sha256', 'my awesome string');
|
||||
result.should.equal(
|
||||
'97f13a1635524dd41daca6601e5d9fe07e10e62790851e527b039851b1f8b9a1',
|
||||
);
|
||||
done();
|
||||
});
|
||||
|
||||
it('z.hmac', (done) => {
|
||||
const result = z.hmac('sha1', 'secret', 'signme');
|
||||
result.should.equal('f67a0be1fa49a3f1dbd659726d8983b838ee6e7d');
|
||||
done();
|
||||
});
|
||||
|
||||
it('z.snipify', (done) => {
|
||||
const result = z.snipify('something');
|
||||
result.should.equal(':censored:9:720a531ca0:');
|
||||
done();
|
||||
});
|
||||
|
||||
it('z.request - sync', () => {
|
||||
const bundleRequest = {
|
||||
method: 'GET',
|
||||
url: `${HTTPBIN_URL}/get`,
|
||||
params: {
|
||||
hello: 'world',
|
||||
},
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
auth: null,
|
||||
data: null,
|
||||
};
|
||||
|
||||
const response = z.request(bundleRequest);
|
||||
response.should.have.property('status_code');
|
||||
response.should.have.property('headers');
|
||||
response.should.have.property('content');
|
||||
|
||||
response.status_code.should.eql(200);
|
||||
const results = JSON.parse(response.content);
|
||||
results.args.should.deepEqual({ hello: ['world'] });
|
||||
results.headers.Accept.should.deepEqual(['application/json']);
|
||||
});
|
||||
|
||||
it('z.request - async', (done) => {
|
||||
const bundleRequest = {
|
||||
method: 'POST',
|
||||
url: `${HTTPBIN_URL}/post`,
|
||||
params: {
|
||||
hello: 'world',
|
||||
},
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
auth: null,
|
||||
data: JSON.stringify({
|
||||
world: 'hello',
|
||||
}),
|
||||
};
|
||||
|
||||
z.request(bundleRequest, (error, response) => {
|
||||
should(error).eql(null);
|
||||
response.should.have.property('status_code');
|
||||
response.should.have.property('headers');
|
||||
response.should.have.property('content');
|
||||
|
||||
response.status_code.should.eql(200);
|
||||
|
||||
const results = JSON.parse(response.content);
|
||||
results.args.should.eql({ hello: ['world'] });
|
||||
|
||||
// Current version of httpbin.zapier-tooling.com encodes the input in
|
||||
// base64 and returns it, so we need to decode it here.
|
||||
const [header, encodedBody] = results.data.split(',');
|
||||
header.should.eql('data:application/octet-stream;base64');
|
||||
|
||||
const decodedBody = Buffer.from(encodedBody, 'base64').toString('utf8');
|
||||
decodedBody.should.eql(bundleRequest.data);
|
||||
results.headers.Accept.should.deepEqual(['application/json']);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('z.JSON.parse', (done) => {
|
||||
const result = z.JSON.parse('{"hello": "world"}');
|
||||
result.should.have.property('hello');
|
||||
result.hello.should.eql('world');
|
||||
|
||||
const invalidJsonString = '{invalid"hello": "world"}';
|
||||
|
||||
try {
|
||||
z.JSON.parse(invalidJsonString);
|
||||
} catch (e) {
|
||||
e.name.should.eql('Error');
|
||||
e.message.should.eql(
|
||||
`Error parsing response. We got: "${invalidJsonString}"`,
|
||||
);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('z.JSON.stringify', (done) => {
|
||||
const result = z.JSON.stringify({
|
||||
hello: 'world',
|
||||
});
|
||||
result.should.equal('{"hello":"world"}');
|
||||
done();
|
||||
});
|
||||
|
||||
it('z.AWS', (done) => {
|
||||
const AWS = z.AWS();
|
||||
AWS.config.getCredentials(done);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue