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.
- package/LICENSE +21 -0
- package/README.md +179 -0
- package/package.json +52 -0
- package/src/commands/config.js +196 -0
- package/src/commands/contact.js +210 -0
- package/src/commands/dns.js +384 -0
- package/src/commands/domain.js +329 -0
- package/src/index.js +240 -0
- package/src/lib/config.js +72 -0
- package/src/lib/locale.js +112 -0
- package/src/lib/output.js +191 -0
- package/src/lib/ui.js +263 -0
- package/src/lib/wapi.js +323 -0
package/src/lib/wapi.js
ADDED
|
@@ -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
|
+
}
|