aeglis-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +150 -0
- package/package.json +17 -0
package/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
const FormData = require('form-data');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
6
|
+
class Aeglis {
|
|
7
|
+
/**
|
|
8
|
+
* Initialize the Aeglis SDK
|
|
9
|
+
* @param {string} apiKey - Your B2B API Key from the Aeglis Dashboard
|
|
10
|
+
*/
|
|
11
|
+
constructor(apiKey) {
|
|
12
|
+
if (!apiKey || typeof apiKey !== 'string') {
|
|
13
|
+
throw new Error('Aeglis Initialization Error: A valid API key is required.');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
this.apiKey = apiKey;
|
|
17
|
+
this.baseURL = 'https://api.aeglis.com/v3/api';
|
|
18
|
+
|
|
19
|
+
// Base HTTP Client for standard JSON requests
|
|
20
|
+
this.client = axios.create({
|
|
21
|
+
baseURL: this.baseURL,
|
|
22
|
+
headers: {
|
|
23
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
24
|
+
'Content-Type': 'application/json'
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 🛡️ QUICK SCAN (Synchronous)
|
|
31
|
+
* Best for short texts, links, and messages.
|
|
32
|
+
* @param {string} inputText - The text or URL to scan.
|
|
33
|
+
* @param {string} [endUserId='anonymous'] - Optional tracking ID for your internal system.
|
|
34
|
+
* @returns {Promise<Object>} Scan results containing risk_level.
|
|
35
|
+
*/
|
|
36
|
+
async scan(inputText, endUserId = 'anonymous') {
|
|
37
|
+
if (!inputText) {
|
|
38
|
+
throw new Error('Aeglis Error: inputText is required for Quick Scan.');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const response = await this.client.post('/scan', {
|
|
43
|
+
input_text: inputText,
|
|
44
|
+
end_user_id: endUserId
|
|
45
|
+
});
|
|
46
|
+
return response.data;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
this._handleApiError(error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 🔍 DEEP SCAN (Asynchronous File Scanning)
|
|
54
|
+
* Triggers your configured Webhook upon completion.
|
|
55
|
+
* @param {string} filePath - Absolute or relative path to the file on disk.
|
|
56
|
+
* @param {Object} [options={}] - Additional scanning options.
|
|
57
|
+
* @param {string} [options.inputText=''] - Optional context text to accompany the file.
|
|
58
|
+
* @param {string} [options.endUserId='anonymous'] - Your system's reference ID (returned in webhook).
|
|
59
|
+
* @returns {Promise<Object>} Acknowledgment of task processing.
|
|
60
|
+
*/
|
|
61
|
+
async deepScan(filePath, options = {}) {
|
|
62
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
63
|
+
throw new Error('Aeglis Error: A valid file path is required for Deep Scan.');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const inputText = options.inputText || '';
|
|
67
|
+
const endUserId = options.endUserId || 'anonymous';
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const form = new FormData();
|
|
71
|
+
|
|
72
|
+
// Append file stream
|
|
73
|
+
form.append('file', fs.createReadStream(filePath));
|
|
74
|
+
|
|
75
|
+
// Append optional fields matching FastAPI requirements
|
|
76
|
+
if (inputText) {
|
|
77
|
+
form.append('input_text', inputText);
|
|
78
|
+
}
|
|
79
|
+
if (endUserId) {
|
|
80
|
+
form.append('end_user_id', endUserId);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Execute multipart/form-data request
|
|
84
|
+
const response = await axios.post(`${this.baseURL}/deep-scan`, form, {
|
|
85
|
+
headers: {
|
|
86
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
87
|
+
...form.getHeaders()
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return response.data;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
this._handleApiError(error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* ⚡ WEBHOOK VERIFICATION (Security)
|
|
99
|
+
* Verifies the authenticity of incoming webhooks using HMAC SHA-256.
|
|
100
|
+
* @param {string|Buffer} rawPayload - The raw, unparsed request body.
|
|
101
|
+
* @param {string} signatureHeader - The 'x-aeglis-signature' header value.
|
|
102
|
+
* @param {string} webhookSecret - Your Endpoint Secret from the dashboard.
|
|
103
|
+
* @returns {Object} The parsed JSON payload if verification succeeds.
|
|
104
|
+
*/
|
|
105
|
+
verifyWebhook(rawPayload, signatureHeader, webhookSecret) {
|
|
106
|
+
if (!rawPayload || !signatureHeader || !webhookSecret) {
|
|
107
|
+
throw new Error('Aeglis Webhook Error: Missing payload, signature header, or secret.');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Ensure payload is a raw string, not a parsed object
|
|
111
|
+
const payloadString = Buffer.isBuffer(rawPayload)
|
|
112
|
+
? rawPayload.toString('utf8')
|
|
113
|
+
: typeof rawPayload === 'object'
|
|
114
|
+
? JSON.stringify(rawPayload)
|
|
115
|
+
: rawPayload;
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
// Re-create the signature using the Aeglis 'v1=' standard
|
|
119
|
+
const expectedSignature = 'v1=' + crypto
|
|
120
|
+
.createHmac('sha256', webhookSecret)
|
|
121
|
+
.update(payloadString)
|
|
122
|
+
.digest('hex');
|
|
123
|
+
|
|
124
|
+
// Prevent Timing Attacks during comparison
|
|
125
|
+
const expectedBuffer = Buffer.from(expectedSignature, 'utf8');
|
|
126
|
+
const signatureBuffer = Buffer.from(signatureHeader, 'utf8');
|
|
127
|
+
|
|
128
|
+
if (expectedBuffer.length !== signatureBuffer.length ||
|
|
129
|
+
!crypto.timingSafeEqual(signatureBuffer, expectedBuffer)) {
|
|
130
|
+
throw new Error('Signature Mismatch');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return JSON.parse(payloadString);
|
|
134
|
+
|
|
135
|
+
} catch (error) {
|
|
136
|
+
throw new Error(`Aeglis Webhook Verification Failed: Invalid Signature or Payload format. Attempted spoofing blocked.`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Internal Error Handler for cleaner console outputs
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
144
|
+
_handleApiError(error) {
|
|
145
|
+
const message = error.response?.data?.detail || error.response?.data?.message || error.message;
|
|
146
|
+
throw new Error(`Aeglis API Error: ${message}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = Aeglis;
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aeglis-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Node.js SDK for the Aeglis Security API.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"author": "Aeglis Systems",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"type": "commonjs",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"axios": "^1.16.1",
|
|
15
|
+
"form-data": "^4.0.5"
|
|
16
|
+
}
|
|
17
|
+
}
|