You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
3.7 KiB

import rest from 'superagent';
import sha1 from 'sha1';
import readline from 'readline';
export class OvhApi{
constructor({credentials, logs = true}){
this.credentials = credentials;
this.log = logs ? this.requestLogs : ()=>{};
this.baseUrl = this.credentials.apiUrl;
this.methods = {get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', path: 'PATCH'};
this.rl = readline.createInterface({
input: process.stdin
});
}
async sendRequest({
path,
body={},
getMethod=rest=>rest.get,
header={accept: 'json'}
}){
let request = getMethod(rest)(`${this.baseUrl}${path}`);
await Object.keys(header).forEach(key => request.set(key, header[key]));
return await request.send(body).then(res => {
this.log({path, header, body, res: JSON.parse(res.text)});
return JSON.parse(res.text);
}).catch(err => {
this.log({path, header, body, err: err?.response?.text});
return false;
});
}
requestLogs({path, header, body, res, err}){
console.log(
`\napi request at ${path} =>`,
'header:', header,
'body:', body,
'\napi response =>'
);
console.assert(res) || console.error(err);
}
async sendSignedRequest({
path,
body={},
getMethod=rest=>rest.get,
header={accept: 'json'},
timestamp = (Date.now()/1000).toFixed()
}){
header['X-Ovh-Timestamp'] = timestamp;
header['X-Ovh-Consumer'] = this.credentials.consumerKey || await this.getConsumerKey();
header['X-Ovh-Application'] = this.credentials.applicationKey;
header['X-Ovh-Signature'] = this.getSignature({
method: getMethod(this.methods),
query: this.baseUrl+path,
body: JSON.stringify(body),
timestamp
});
return await this.sendRequest({path, body, getMethod, header});
}
getSignature({method = 'GET', query, body='', timestamp}){
return '$1$' + sha1(
this.credentials.applicationSecret+'+'+
this.credentials.consumerKey+'+'+
method+'+'+query+'+'+body+'+'+timestamp
);
}
async getConsumerKey(){
let res = await this.sendRequest({
path: '/auth/credential',
getMethod: rest=>rest.post,
header: {
'X-Ovh-Application': this.credentials.applicationKey,
'Content-type': 'application/json'
},
body: {
accessRules: [
{method: 'GET', path: '/domain/zone/*'},
{method: 'POST', path: '/domain/zone/*'},
{method: 'PUT', path: '/domain/zone/*'}
]
}
});
this.credentials.consumerKey = res.consumerKey;
console.log('please validate on ovh site:');
console.log(res.validationUrl);
return this.rl.question('continue? (Y/n)', async (input) => {
switch (input) {
case 'n': process.exit(); break;
default: return res.consumerKey;
}
});
}
async updateRecord({zone, subDomain, id, target, ttl = 3600, fieldType = 'A'}, domain = zone){
return await this.sendSignedRequest({
path: `/domain/zone/${domain}/record/${id}`,
getMethod: rest=>rest.put,
body: {subDomain, target, ttl}
});
}
async getApiTime(){
return await this.sendRequest({
path: '/auth/time'
});
}
async getRecords({domain, fieldType = undefined, subDomain = undefined}){
return await this.sendSignedRequest({
path: `/domain/zone/${domain}/record`,
body: {
fieldType,
subDomain
}
});
}
async getRecord({domain, id}){
return await this.sendSignedRequest({
path: `/domain/zone/${domain}/record/${id}`
});
}
async refreshZone(zone){
return await this.sendSignedRequest({
path: `/domain/zone/${zone}/refresh`,
getMethod: rest=>rest.post
});
}
}