sms-verification-api 0.9.1 → 0.9.7

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/src/sns.js DELETED
@@ -1,236 +0,0 @@
1
- /**
2
- * AWS SNS HTTP API Client for Cloudflare Workers
3
- * @class SNSClient
4
- */
5
- class SNSClient {
6
- /**
7
- * Create a new SNS client instance
8
- * @param {Object} options - Configuration options
9
- * @param {string} options.accessKeyId - AWS access key ID
10
- * @param {string} options.secretAccessKey - AWS secret access key
11
- * @param {string} [options.region='us-east-1'] - AWS region
12
- */
13
- constructor(options = {}) {
14
- this.accessKeyId = options.accessKeyId;
15
- this.secretAccessKey = options.secretAccessKey;
16
- this.region = options.region || 'us-east-1';
17
- this.endpoint = `https://sns.${this.region}.amazonaws.com`;
18
- }
19
-
20
- // Convert string to Uint8Array
21
- stringToUint8Array(str) {
22
- return new TextEncoder().encode(str);
23
- }
24
-
25
- // Convert Uint8Array to hex string
26
- arrayBufferToHex(buffer) {
27
- return Array.from(new Uint8Array(buffer))
28
- .map(b => b.toString(16).padStart(2, '0'))
29
- .join('');
30
- }
31
-
32
- // AWS Signature Version 4 signing using Web Crypto API
33
- async sign(method, url, headers, payload) {
34
- const now = new Date();
35
- const amzDate = now.toISOString().replace(/[:\-]|\.\d{3}/g, '');
36
- const dateStamp = amzDate.substr(0, 8);
37
-
38
- // Create canonical request
39
- const canonicalUri = '/';
40
- const canonicalQuerystring = url.split('?')[1] || '';
41
-
42
- // Add required headers
43
- headers['host'] = `sns.${this.region}.amazonaws.com`;
44
- headers['x-amz-date'] = amzDate;
45
-
46
- // Calculate payload hash
47
- const payloadHash = await crypto.subtle.digest('SHA-256', this.stringToUint8Array(payload))
48
- .then(buffer => this.arrayBufferToHex(buffer));
49
- headers['x-amz-content-sha256'] = payloadHash;
50
-
51
- // Create canonical headers
52
- const sortedHeaders = Object.keys(headers).sort().map(key =>
53
- `${key.toLowerCase()}:${headers[key]}`
54
- ).join('\n');
55
-
56
- const signedHeaders = Object.keys(headers).sort().map(key =>
57
- key.toLowerCase()
58
- ).join(';');
59
-
60
- const canonicalRequest = [
61
- method,
62
- canonicalUri,
63
- canonicalQuerystring,
64
- sortedHeaders,
65
- '',
66
- signedHeaders,
67
- payloadHash
68
- ].join('\n');
69
-
70
- // Create string to sign
71
- const algorithm = 'AWS4-HMAC-SHA256';
72
- const credentialScope = `${dateStamp}/${this.region}/sns/aws4_request`;
73
-
74
- const canonicalRequestHash = await crypto.subtle.digest('SHA-256', this.stringToUint8Array(canonicalRequest))
75
- .then(buffer => this.arrayBufferToHex(buffer));
76
-
77
- const stringToSign = [
78
- algorithm,
79
- amzDate,
80
- credentialScope,
81
- canonicalRequestHash
82
- ].join('\n');
83
-
84
- // Calculate signature using Web Crypto API
85
- const kDate = await crypto.subtle.importKey(
86
- 'raw',
87
- this.stringToUint8Array(`AWS4${this.secretAccessKey}`),
88
- { name: 'HMAC', hash: 'SHA-256' },
89
- false,
90
- ['sign']
91
- ).then(key => crypto.subtle.sign('HMAC', key, this.stringToUint8Array(dateStamp)));
92
-
93
- const kRegion = await crypto.subtle.importKey(
94
- 'raw',
95
- kDate,
96
- { name: 'HMAC', hash: 'SHA-256' },
97
- false,
98
- ['sign']
99
- ).then(key => crypto.subtle.sign('HMAC', key, this.stringToUint8Array(this.region)));
100
-
101
- const kService = await crypto.subtle.importKey(
102
- 'raw',
103
- kRegion,
104
- { name: 'HMAC', hash: 'SHA-256' },
105
- false,
106
- ['sign']
107
- ).then(key => crypto.subtle.sign('HMAC', key, this.stringToUint8Array('sns')));
108
-
109
- const kSigning = await crypto.subtle.importKey(
110
- 'raw',
111
- kService,
112
- { name: 'HMAC', hash: 'SHA-256' },
113
- false,
114
- ['sign']
115
- ).then(key => crypto.subtle.sign('HMAC', key, this.stringToUint8Array('aws4_request')));
116
-
117
- const signature = await crypto.subtle.importKey(
118
- 'raw',
119
- kSigning,
120
- { name: 'HMAC', hash: 'SHA-256' },
121
- false,
122
- ['sign']
123
- ).then(key => crypto.subtle.sign('HMAC', key, this.stringToUint8Array(stringToSign)))
124
- .then(buffer => this.arrayBufferToHex(buffer));
125
-
126
- // Create authorization header
127
- headers['authorization'] = `${algorithm} Credential=${this.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
128
-
129
- return headers;
130
- }
131
-
132
- // Make HTTP request to SNS
133
- async makeRequest(action, params = {}) {
134
- const queryParams = new URLSearchParams({
135
- Action: action,
136
- Version: '2010-03-31',
137
- ...params
138
- });
139
-
140
- const url = `${this.endpoint}/?${queryParams.toString()}`;
141
- const payload = '';
142
- const headers = {
143
- 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
144
- };
145
-
146
- // Sign the request
147
- const signedHeaders = await this.sign('GET', url, headers, payload);
148
-
149
- try {
150
- const response = await fetch(url, {
151
- method: 'GET',
152
- headers: signedHeaders
153
- });
154
-
155
- const text = await response.text();
156
-
157
- if (!response.ok) {
158
- throw new Error(`SNS API Error: ${response.status} - ${text}`);
159
- }
160
-
161
- return this.parseXMLResponse(text);
162
- } catch (error) {
163
- throw new Error(`SNS Request failed: ${error.message}`);
164
- }
165
- }
166
-
167
- // Parse XML response (simplified for Cloudflare Workers)
168
- parseXMLResponse(xmlText) {
169
- // Simple XML parsing for common SNS responses
170
- // Note: DOMParser is not available in Cloudflare Workers, so we'll use regex parsing
171
- // This is a simplified parser for SNS responses
172
-
173
- // Handle common SNS responses using regex parsing
174
- const messageIdMatch = xmlText.match(/<MessageId>([^<]+)<\/MessageId>/);
175
- const topicArnMatch = xmlText.match(/<TopicArn>([^<]+)<\/TopicArn>/);
176
- const subscriptionArnMatch = xmlText.match(/<SubscriptionArn>([^<]+)<\/SubscriptionArn>/);
177
-
178
- if (messageIdMatch) {
179
- return { MessageId: messageIdMatch[1] };
180
- }
181
-
182
- if (topicArnMatch) {
183
- return { TopicArn: topicArnMatch[1] };
184
- }
185
-
186
- if (subscriptionArnMatch) {
187
- return { SubscriptionArn: subscriptionArnMatch[1] };
188
- }
189
-
190
- // Fallback: return raw text for unknown responses
191
- return { raw: xmlText };
192
- }
193
- }
194
-
195
- // Global SNS client instance
196
- let defaultClient = null;
197
-
198
- // Create SNS client
199
- export function createClient(options = {}) {
200
- defaultClient = new SNSClient(options);
201
- return defaultClient;
202
- }
203
-
204
- // Send SMS function
205
- export function sendSMS(textmessage, phone, senderid, SMSType, callback, client = null) {
206
- const snsClient = client || defaultClient;
207
-
208
- if (!snsClient) {
209
- return callback({ err: new Error('SNS client not initialized. Call createClient() first.') });
210
- }
211
-
212
- const params = {
213
- Message: textmessage,
214
- PhoneNumber: phone,
215
- 'MessageAttributes.entry.1.Name': 'AWS.SNS.SMS.SenderID',
216
- 'MessageAttributes.entry.1.Value.DataType': 'String',
217
- 'MessageAttributes.entry.1.Value.StringValue': senderid,
218
- 'MessageAttributes.entry.2.Name': 'AWS.SNS.SMS.SMSType',
219
- 'MessageAttributes.entry.2.Value.DataType': 'String',
220
- 'MessageAttributes.entry.2.Value.StringValue': SMSType
221
- };
222
-
223
- snsClient.makeRequest('Publish', params)
224
- .then(response => {
225
- callback(undefined, response.MessageId);
226
- })
227
- .catch(error => {
228
- callback({ err: error, 'err.stack': error.stack });
229
- });
230
- }
231
-
232
- // Export for compatibility
233
- export default {
234
- createClient,
235
- sendSMS
236
- };
File without changes
File without changes
File without changes