wedos-cli 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.
@@ -0,0 +1,323 @@
1
+ import crypto from 'crypto';
2
+
3
+ const API_URL = 'https://api.wedos.com/wapi/json';
4
+
5
+ /**
6
+ * Generate WAPI auth string
7
+ * Format: sha1(username + sha1(password) + hour)
8
+ * Hour is 00-23 in Europe/Prague timezone
9
+ */
10
+ function generateAuth(username, password) {
11
+ const pragueDate = new Date().toLocaleString('en-US', { timeZone: 'Europe/Prague' });
12
+ const hour = new Date(pragueDate).getHours().toString().padStart(2, '0');
13
+
14
+ const passwordHash = crypto.createHash('sha1').update(password).digest('hex');
15
+ const authString = username + passwordHash + hour;
16
+
17
+ return crypto.createHash('sha1').update(authString).digest('hex');
18
+ }
19
+
20
+ /**
21
+ * WAPI Client for WEDOS API
22
+ */
23
+ export class WapiClient {
24
+ constructor(config) {
25
+ this.username = config.username;
26
+ this.password = config.password;
27
+ this.testMode = config.testMode || false;
28
+ }
29
+
30
+ /**
31
+ * Make API request
32
+ */
33
+ async request(command, data = {}) {
34
+ const auth = generateAuth(this.username, this.password);
35
+
36
+ const requestData = {
37
+ user: this.username,
38
+ auth: auth,
39
+ command: command,
40
+ clTRID: `wedos-cli-${Date.now()}`,
41
+ ...(this.testMode && { test: 1 }),
42
+ ...(Object.keys(data).length > 0 && { data })
43
+ };
44
+
45
+ // WEDOS API expects form-urlencoded with 'request' parameter containing JSON
46
+ const formData = new URLSearchParams();
47
+ formData.append('request', JSON.stringify({ request: requestData }));
48
+
49
+ const response = await fetch(API_URL, {
50
+ method: 'POST',
51
+ headers: {
52
+ 'Content-Type': 'application/x-www-form-urlencoded',
53
+ },
54
+ body: formData.toString()
55
+ });
56
+
57
+ if (!response.ok) {
58
+ throw new Error(`HTTP error: ${response.status}`);
59
+ }
60
+
61
+ const result = await response.json();
62
+
63
+ if (!result.response) {
64
+ throw new Error('Invalid API response');
65
+ }
66
+
67
+ return result.response;
68
+ }
69
+
70
+ // =====================
71
+ // Basic Commands
72
+ // =====================
73
+
74
+ async ping() {
75
+ return this.request('ping');
76
+ }
77
+
78
+ async pollReq() {
79
+ return this.request('poll-req');
80
+ }
81
+
82
+ async pollAck(msgid) {
83
+ return this.request('poll-ack', { msgid });
84
+ }
85
+
86
+ // =====================
87
+ // Domain Commands
88
+ // =====================
89
+
90
+ async domainsList(status = null) {
91
+ const data = status ? { status } : {};
92
+ return this.request('domains-list', data);
93
+ }
94
+
95
+ async domainCheck(domains) {
96
+ const name = Array.isArray(domains) ? domains.join(',') : domains;
97
+ return this.request('domain-check', { name });
98
+ }
99
+
100
+ async domainInfo(domains) {
101
+ const name = Array.isArray(domains) ? domains.join(',') : domains;
102
+ return this.request('domain-info', { name });
103
+ }
104
+
105
+ async domainCreate(options) {
106
+ const data = {
107
+ name: options.name,
108
+ period: options.period || 1,
109
+ owner_c: options.ownerContact,
110
+ rules: options.rules,
111
+ };
112
+
113
+ if (options.adminContact) {
114
+ data.admin_c = options.adminContact;
115
+ }
116
+
117
+ // DNS configuration
118
+ if (options.nsset) {
119
+ data.nsset = options.nsset;
120
+ } else if (options.dns) {
121
+ data.dns = options.dns;
122
+ } else {
123
+ // Default to WEDOS NSSET
124
+ data.nsset = 'WEDOS';
125
+ }
126
+
127
+ return this.request('domain-create', data);
128
+ }
129
+
130
+ async domainRenew(name, period = 1) {
131
+ return this.request('domain-renew', { name, period });
132
+ }
133
+
134
+ async domainUpdateNs(name, nsset = null, dns = null) {
135
+ const data = { name };
136
+ if (nsset) {
137
+ data.nsset = nsset;
138
+ } else if (dns) {
139
+ data.dns = dns;
140
+ }
141
+ return this.request('domain-update-ns', data);
142
+ }
143
+
144
+ async domainTransferCheck(name) {
145
+ return this.request('domain-transfer-check', { name });
146
+ }
147
+
148
+ async domainTransfer(options) {
149
+ const data = {
150
+ name: options.name,
151
+ auth_info: options.authInfo,
152
+ rules: options.rules,
153
+ };
154
+
155
+ if (options.ownerContact) {
156
+ data.owner_c = options.ownerContact;
157
+ }
158
+
159
+ if (options.nsset) {
160
+ data.nsset = options.nsset;
161
+ } else if (options.dns) {
162
+ data.dns = options.dns;
163
+ }
164
+
165
+ return this.request('domain-transfer', data);
166
+ }
167
+
168
+ async domainSendAuthInfo(name) {
169
+ return this.request('domain-send-auth-info', { name });
170
+ }
171
+
172
+ async domainTldPeriodCheck(tld, period) {
173
+ return this.request('domain-tld-period-check', { tld, period });
174
+ }
175
+
176
+ // =====================
177
+ // Contact Commands
178
+ // =====================
179
+
180
+ async contactCheck(tld, cname) {
181
+ return this.request('contact-check', { tld, cname });
182
+ }
183
+
184
+ async contactInfo(tld, cname, authInfo = null) {
185
+ const data = { tld, cname };
186
+ if (authInfo) {
187
+ data.auth_info = authInfo;
188
+ }
189
+ return this.request('contact-info', data);
190
+ }
191
+
192
+ async contactCreate(tld, contact) {
193
+ return this.request('contact-create', {
194
+ tld,
195
+ contact: {
196
+ fname: contact.firstName,
197
+ lname: contact.lastName,
198
+ email: contact.email,
199
+ addr_street: contact.street,
200
+ addr_city: contact.city,
201
+ addr_zip: contact.zip,
202
+ addr_country: contact.country,
203
+ phone: contact.phone,
204
+ ...(contact.company && { company: contact.company }),
205
+ ...(contact.fax && { fax: contact.fax }),
206
+ ...(contact.identType && { ident_type: contact.identType }),
207
+ ...(contact.ident && { ident: contact.ident }),
208
+ ...(contact.notifyEmail && { notify_email: contact.notifyEmail }),
209
+ ...(contact.cname && { cname: contact.cname }),
210
+ }
211
+ });
212
+ }
213
+
214
+ async contactUpdate(tld, cname, authInfo, contact) {
215
+ return this.request('contact-update', {
216
+ tld,
217
+ cname,
218
+ auth_info: authInfo,
219
+ contact
220
+ });
221
+ }
222
+
223
+ // =====================
224
+ // DNS Commands
225
+ // =====================
226
+
227
+ async dnsDomainsList(options = {}) {
228
+ return this.request('dns-domains-list', options);
229
+ }
230
+
231
+ async dnsDomainInfo(name) {
232
+ return this.request('dns-domain-info', { name });
233
+ }
234
+
235
+ async dnsDomainAdd(options) {
236
+ const data = {
237
+ name: options.name,
238
+ type: options.type || 'primary',
239
+ };
240
+
241
+ if (options.axfrEnabled !== undefined) {
242
+ data.axfr_enabled = options.axfrEnabled ? 1 : 0;
243
+ }
244
+
245
+ if (options.axfrIps) {
246
+ data.axfr_ips = options.axfrIps;
247
+ }
248
+
249
+ if (options.type === 'secondary') {
250
+ data.primary_ip = options.primaryIp;
251
+ }
252
+
253
+ return this.request('dns-domain-add', data);
254
+ }
255
+
256
+ async dnsDomainDelete(name) {
257
+ return this.request('dns-domain-delete', { name });
258
+ }
259
+
260
+ async dnsDomainCommit(name) {
261
+ return this.request('dns-domain-commit', { name });
262
+ }
263
+
264
+ async dnsRowsList(domain) {
265
+ return this.request('dns-rows-list', { domain });
266
+ }
267
+
268
+ async dnsRowDetail(name, rowId) {
269
+ return this.request('dns-row-detail', { name, row_id: rowId });
270
+ }
271
+
272
+ async dnsRowAdd(options) {
273
+ return this.request('dns-row-add', {
274
+ domain: options.domain,
275
+ name: options.name,
276
+ ttl: options.ttl || 3600,
277
+ type: options.type,
278
+ rdata: options.rdata,
279
+ ...(options.comment && { auth_comment: options.comment }),
280
+ });
281
+ }
282
+
283
+ async dnsRowUpdate(domain, rowId, options) {
284
+ return this.request('dns-row-update', {
285
+ domain,
286
+ row_id: rowId,
287
+ ttl: options.ttl,
288
+ rdata: options.rdata,
289
+ });
290
+ }
291
+
292
+ async dnsRowDelete(domain, rowId) {
293
+ return this.request('dns-row-delete', { domain, row_id: rowId });
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Response code descriptions
299
+ */
300
+ export const RESPONSE_CODES = {
301
+ 1000: 'OK',
302
+ 1001: 'Pending (async operation)',
303
+ 2201: 'Unsupported TLD',
304
+ 2202: 'Invalid domain name',
305
+ 2203: 'Invalid period',
306
+ 3002: 'Insufficient credit',
307
+ 3201: 'Domain already registered',
308
+ 3204: 'Domain in quarantine',
309
+ 3205: 'Domain reserved',
310
+ 3206: 'Domain blocked',
311
+ 3217: 'Registry connection failed',
312
+ 3218: 'Transfer not possible',
313
+ 3222: 'Failed to get domain info',
314
+ 5001: 'Internal error',
315
+ };
316
+
317
+ export function isSuccess(code) {
318
+ return code >= 1000 && code < 2000;
319
+ }
320
+
321
+ export function isError(code) {
322
+ return code >= 2000;
323
+ }