Skip to content

Commit ef545e6

Browse files
committed
lifecycle capable
1 parent e0f4786 commit ef545e6

File tree

4 files changed

+242
-196
lines changed

4 files changed

+242
-196
lines changed

lib/callback.js

Lines changed: 0 additions & 120 deletions
This file was deleted.

lib/index.js

Lines changed: 124 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
var VERSION = 0.2;
2-
1+
var VERSION = 0.3;
32
var util = require('util');
3+
var assert = require('assert');
44
var aws = require('aws-sdk');
55
var s3 = new aws.S3({apiVersion: '2006-03-01'});
66
var http = require('https');
@@ -9,27 +9,111 @@ var crypto = require('crypto');
99

1010
// replace below with your credentials in the form key:secret
1111
// to create your key go to https://scanii.com/account/settings/keys
12-
var SCANII_CREDS = 'KEY:SECRET';
12+
var SCANII_CREDS = 'CHANGE';
13+
// replace with the URL of your callback lambda function
14+
var CALLBACK_URL = 'ME';
15+
16+
17+
onFindings = function (bucket, key, result, context) {
18+
console.log('RESULT:', internalId(bucket, key), 'has findings', result.findings);
19+
var pending = true;
20+
21+
// sample code that delete objects with findings from S3:
22+
var req = s3.deleteObject({Bucket: bucket, Key: key});
23+
req.on('success', function (response) {
24+
console.log(console.log('file', internalId(bucket, key), 'deleted'));
25+
context.succeed(util.format('callback for file %s completed successful', result.id));
26+
pending = false;
27+
28+
}).on('error', function (response) {
29+
console.log(console.log('error while deleting', internalId(bucket, key)));
30+
context.fail(response);
31+
pending = false;
32+
});
33+
req.send();
34+
var waitWhilePending = function () {
35+
if (pending) {
36+
console.log('waiting');
37+
setTimeout(waitWhilePending, 100);
38+
}
39+
};
40+
setTimeout(waitWhilePending, 100);
41+
42+
};
43+
44+
onNoFindings = function (bucket, key, result, context) {
45+
console.log('RESULT:', internalId(bucket, key), 'has no findings');
46+
context.succeed(util.format('callback for file %s completed successful', result.id));
47+
48+
};
49+
1350

14-
// Do not edit below this line
51+
//------------------------------- Do not edit below this line ----------------------------------------------
52+
53+
// if the credentials are passed via an env variable we honor it:
54+
if (process.env.SCANII_CREDS !== undefined) {
55+
console.log('loading credentials from environment variable');
56+
SCANII_CREDS = process.env.SCANII_CREDS;
57+
}
1558

1659
const API_ENDPOINT = '/v2.1/files/';
1760

18-
console.log('Loading function v', VERSION);
61+
console.log('loading function v', VERSION);
1962

2063
var KEY = SCANII_CREDS.split(':')[0];
2164
var SECRET = SCANII_CREDS.split(':')[1];
65+
console.log('using key', KEY);
66+
67+
var internalId = function (bucket, key) {
68+
return util.format('s3://%s/%s', bucket, key);
69+
};
70+
71+
var generateSignature = function (bucket, key) {
72+
return crypto.createHmac('sha1', SECRET).update(internalId(bucket, key)).digest('hex');
73+
};
74+
75+
/**
76+
* Handles HTTP result callback
77+
*/
78+
var handleCallback = function (event, context) {
79+
console.log('handling callback event');
80+
81+
var r = event;
82+
//console.log('response:', JSON.stringify(r, null, 2));
83+
console.log("metadata:", r.metadata);
84+
85+
// callback sanity checks
86+
assert.ok(r.id !== undefined, "no id provided");
87+
assert.ok(r.metadata !== undefined, "no metadata supplied");
88+
assert.ok(r.metadata.bucket !== undefined, "no bucket supplied in metadata");
89+
assert.ok(r.metadata.key !== undefined, "no key supplied in metadata");
90+
assert.ok(r.metadata.signature !== undefined, "no signature supplied in metadata");
91+
92+
// now asserting bucket/keys were not tampered with:
93+
assert.ok(r.metadata.signature == generateSignature(r.metadata.bucket, r.metadata.key), "invalid signature");
94+
console.log('signature check passed for signature', r.metadata.signature);
95+
96+
if (r.findings !== undefined) {
97+
if (r.findings.length > 0) {
98+
onFindings(r.metadata.bucket, r.metadata.key, r, context);
99+
} else {
100+
onNoFindings(r.metadata.bucket, r.metadata.key, r, context);
101+
}
102+
}
22103

23-
var internalId = function(bucket, key) {
24-
return util.format('processing s3://%s/%s', bucket, key);
25104
};
26105

27-
exports.handler = function (event, context) {
28-
console.log('Received event:', JSON.stringify(event, null, 2));
106+
107+
/**
108+
* Handles S3 event and submits content for processing
109+
*/
110+
var handleS3Event = function (event, context) {
111+
console.log('handling S3 event');
29112

30113
// Get the object from the event and show its content type
31114
var bucket = event.Records[0].s3.bucket.name;
32-
var key = event.Records[0].s3.object.key;
115+
// see https://forums.aws.amazon.com/thread.jspa?threadID=215813
116+
var key = Object.keys(qs.decode(event.Records[0].s3.object.key))[0];
33117

34118
console.log('processing ' + internalId(bucket, key));
35119

@@ -40,20 +124,21 @@ exports.handler = function (event, context) {
40124
Expires: 3600 // 1 hour
41125
});
42126
console.log('created signed url', url);
43-
console.log('submitting content for processing');
44127

128+
129+
console.log('submitting content for processing');
45130
// signing request
46-
var signature = crypto.createHmac('sha1', SECRET).update(internalId(bucket, key)).digest('hex');
131+
var signature = generateSignature(bucket, key);
47132
console.log('using signature ' + signature);
48133

49134
var payload = qs.stringify({
50135
location: url,
51-
'metadata[hmac]': signature,
52-
'metadata[id]': internalId(bucket, key)
136+
callback: CALLBACK_URL,
137+
'metadata[signature]': signature,
138+
'metadata[bucket]': bucket,
139+
'metadata[key]': key
53140
});
54141

55-
console.log(payload);
56-
57142
var options = {
58143
auth: SCANII_CREDS,
59144
port: 443,
@@ -63,27 +148,41 @@ exports.handler = function (event, context) {
63148
headers: {
64149
'Content-Type': 'application/x-www-form-urlencoded',
65150
'Content-Length': payload.length,
66-
'User-Agent': 'scanii-mu/v' + VERSION
151+
'User-Agent': 'scanii-lambda/v' + VERSION
67152
}
68153
};
69-
154+
console.log(payload);
70155
// calling scanii API v2.1 (http://docs.scanii.com/v2.1/resources.html):
71156
var req = http.request(options, function (res) {
72-
console.log("statusCode: ", res.statusCode);
73157
console.log("headers: ", res.headers);
74158

75159
res.on('data', function (data) {
76160
var serviceResponse = JSON.parse(data);
77-
console.log('file id:', serviceResponse.id);
78-
context.succeed('OK - id ' + serviceResponse.id);
161+
if (res.statusCode == 202) {
162+
console.log('file id:', serviceResponse.id);
163+
context.succeed(serviceResponse.id);
164+
} else {
165+
console.log(serviceResponse);
166+
context.fail(util.format("Error: invalid response from server, message [%s] and http code: %d", serviceResponse.body, res.statusCode));
167+
}
168+
});
169+
res.on('error', function (error) {
170+
context.fail(error);
79171
});
80172
});
81173

82174
req.write(payload);
83175
req.end();
84176

85-
req.on('error', function (error) {
86-
console.log(error);
87-
context.fail(error);
88-
});
89177
};
178+
179+
exports.handler = function (event, context) {
180+
console.log('received event:', JSON.stringify(event, null, 2));
181+
if (event.Records !== undefined) {
182+
handleS3Event(event, context);
183+
} else {
184+
handleCallback(event, context);
185+
}
186+
};
187+
188+
exports.generateSignature = generateSignature;

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "scanii-mu",
3-
"version": "1.0.0",
3+
"version": "0.3.0",
44
"description": "",
55
"main": "index.js",
66
"scripts": {
@@ -11,6 +11,7 @@
1111
"dependencies": {
1212
"aws-lambda-mock-context": "^0.2.0",
1313
"aws-sdk": "^2.2.5",
14+
"chai": "^3.4.1",
1415
"consoleplusplus": "^1.3.0",
1516
"mocha": "^2.3.3"
1617
}

0 commit comments

Comments
 (0)