parent
817cf5ed03
commit
a7d78c0e9b
38 changed files with 2996 additions and 789 deletions
|
@ -80,6 +80,8 @@ function _ensureStringed(thing) {
|
|||
return res;
|
||||
} else if (thing === null) {
|
||||
return null;
|
||||
} else if (thing === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
throw new Error(`unsure of how to jsonify object of type ${typeof thing}`);
|
||||
}
|
||||
|
@ -160,7 +162,9 @@ function _createSocket(url, { certificateAuthority, proxyUrl }) {
|
|||
function _promiseAjax(providedUrl, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = providedUrl || `${options.host}/${options.path}`;
|
||||
log.info(options.type, url);
|
||||
log.info(
|
||||
`${options.type} ${url}${options.unauthenticated ? ' (unauth)' : ''}`
|
||||
);
|
||||
const timeout =
|
||||
typeof options.timeout !== 'undefined' ? options.timeout : 10000;
|
||||
|
||||
|
@ -188,15 +192,26 @@ function _promiseAjax(providedUrl, options) {
|
|||
fetchOptions.headers['Content-Length'] = contentLength;
|
||||
}
|
||||
|
||||
if (options.user && options.password) {
|
||||
const { accessKey, unauthenticated } = options;
|
||||
if (unauthenticated) {
|
||||
if (!accessKey) {
|
||||
throw new Error(
|
||||
'_promiseAjax: mode is aunathenticated, but accessKey was not provided'
|
||||
);
|
||||
}
|
||||
// Access key is already a Base64 string
|
||||
fetchOptions.headers['Unidentified-Access-Key'] = accessKey;
|
||||
} else if (options.user && options.password) {
|
||||
const user = _getString(options.user);
|
||||
const password = _getString(options.password);
|
||||
const auth = _btoa(`${user}:${password}`);
|
||||
fetchOptions.headers.Authorization = `Basic ${auth}`;
|
||||
}
|
||||
|
||||
if (options.contentType) {
|
||||
fetchOptions.headers['Content-Type'] = options.contentType;
|
||||
}
|
||||
|
||||
fetch(url, fetchOptions)
|
||||
.then(response => {
|
||||
let resultPromise;
|
||||
|
@ -292,12 +307,14 @@ function HTTPError(message, providedCode, response, stack) {
|
|||
|
||||
const URL_CALLS = {
|
||||
accounts: 'v1/accounts',
|
||||
attachment: 'v1/attachments',
|
||||
deliveryCert: 'v1/certificate/delivery',
|
||||
supportUnauthenticatedDelivery: 'v1/devices/unauthenticated_delivery',
|
||||
devices: 'v1/devices',
|
||||
keys: 'v2/keys',
|
||||
signed: 'v2/keys/signed',
|
||||
messages: 'v1/messages',
|
||||
attachment: 'v1/attachments',
|
||||
profile: 'v1/profile',
|
||||
signed: 'v2/keys/signed',
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
@ -335,16 +352,21 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
getAttachment,
|
||||
getAvatar,
|
||||
getDevices,
|
||||
getSenderCertificate,
|
||||
registerSupportForUnauthenticatedDelivery,
|
||||
getKeysForNumber,
|
||||
getKeysForNumberUnauth,
|
||||
getMessageSocket,
|
||||
getMyKeys,
|
||||
getProfile,
|
||||
getProfileUnauth,
|
||||
getProvisioningSocket,
|
||||
putAttachment,
|
||||
registerKeys,
|
||||
requestVerificationSMS,
|
||||
requestVerificationVoice,
|
||||
sendMessages,
|
||||
sendMessagesUnauth,
|
||||
setSignedPreKey,
|
||||
};
|
||||
|
||||
|
@ -366,6 +388,8 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
type: param.httpType,
|
||||
user: username,
|
||||
validateResponse: param.validateResponse,
|
||||
unauthenticated: param.unauthenticated,
|
||||
accessKey: param.accessKey,
|
||||
}).catch(e => {
|
||||
const { code } = e;
|
||||
if (code === 200) {
|
||||
|
@ -405,6 +429,23 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
});
|
||||
}
|
||||
|
||||
function getSenderCertificate() {
|
||||
return _ajax({
|
||||
call: 'deliveryCert',
|
||||
httpType: 'GET',
|
||||
responseType: 'json',
|
||||
schema: { certificate: 'string' },
|
||||
});
|
||||
}
|
||||
|
||||
function registerSupportForUnauthenticatedDelivery() {
|
||||
return _ajax({
|
||||
call: 'supportUnauthenticatedDelivery',
|
||||
httpType: 'PUT',
|
||||
responseType: 'json',
|
||||
});
|
||||
}
|
||||
|
||||
function getProfile(number) {
|
||||
return _ajax({
|
||||
call: 'profile',
|
||||
|
@ -413,6 +454,16 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
responseType: 'json',
|
||||
});
|
||||
}
|
||||
function getProfileUnauth(number, { accessKey } = {}) {
|
||||
return _ajax({
|
||||
call: 'profile',
|
||||
httpType: 'GET',
|
||||
urlParameters: `/${number}`,
|
||||
responseType: 'json',
|
||||
unauthenticated: true,
|
||||
accessKey,
|
||||
});
|
||||
}
|
||||
|
||||
function getAvatar(path) {
|
||||
// Using _outerAJAX, since it's not hardcoded to the Signal Server. Unlike our
|
||||
|
@ -449,13 +500,19 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
newPassword,
|
||||
signalingKey,
|
||||
registrationId,
|
||||
deviceName
|
||||
deviceName,
|
||||
options = {}
|
||||
) {
|
||||
const { accessKey } = options;
|
||||
const jsonData = {
|
||||
signalingKey: _btoa(_getString(signalingKey)),
|
||||
supportsSms: false,
|
||||
fetchesMessages: true,
|
||||
registrationId,
|
||||
unidentifiedAccessKey: accessKey
|
||||
? _btoa(_getString(accessKey))
|
||||
: undefined,
|
||||
unrestrictedUnidentifiedAccess: false,
|
||||
};
|
||||
|
||||
let call;
|
||||
|
@ -552,6 +609,43 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
}).then(res => res.count);
|
||||
}
|
||||
|
||||
function handleKeys(res) {
|
||||
if (!Array.isArray(res.devices)) {
|
||||
throw new Error('Invalid response');
|
||||
}
|
||||
res.identityKey = _base64ToBytes(res.identityKey);
|
||||
res.devices.forEach(device => {
|
||||
if (
|
||||
!_validateResponse(device, { signedPreKey: 'object' }) ||
|
||||
!_validateResponse(device.signedPreKey, {
|
||||
publicKey: 'string',
|
||||
signature: 'string',
|
||||
})
|
||||
) {
|
||||
throw new Error('Invalid signedPreKey');
|
||||
}
|
||||
if (device.preKey) {
|
||||
if (
|
||||
!_validateResponse(device, { preKey: 'object' }) ||
|
||||
!_validateResponse(device.preKey, { publicKey: 'string' })
|
||||
) {
|
||||
throw new Error('Invalid preKey');
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
device.preKey.publicKey = _base64ToBytes(device.preKey.publicKey);
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
device.signedPreKey.publicKey = _base64ToBytes(
|
||||
device.signedPreKey.publicKey
|
||||
);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
device.signedPreKey.signature = _base64ToBytes(
|
||||
device.signedPreKey.signature
|
||||
);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
function getKeysForNumber(number, deviceId = '*') {
|
||||
return _ajax({
|
||||
call: 'keys',
|
||||
|
@ -559,41 +653,46 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) {
|
|||
urlParameters: `/${number}/${deviceId}`,
|
||||
responseType: 'json',
|
||||
validateResponse: { identityKey: 'string', devices: 'object' },
|
||||
}).then(res => {
|
||||
if (res.devices.constructor !== Array) {
|
||||
throw new Error('Invalid response');
|
||||
}
|
||||
res.identityKey = _base64ToBytes(res.identityKey);
|
||||
res.devices.forEach(device => {
|
||||
if (
|
||||
!_validateResponse(device, { signedPreKey: 'object' }) ||
|
||||
!_validateResponse(device.signedPreKey, {
|
||||
publicKey: 'string',
|
||||
signature: 'string',
|
||||
})
|
||||
) {
|
||||
throw new Error('Invalid signedPreKey');
|
||||
}
|
||||
if (device.preKey) {
|
||||
if (
|
||||
!_validateResponse(device, { preKey: 'object' }) ||
|
||||
!_validateResponse(device.preKey, { publicKey: 'string' })
|
||||
) {
|
||||
throw new Error('Invalid preKey');
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
device.preKey.publicKey = _base64ToBytes(device.preKey.publicKey);
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
device.signedPreKey.publicKey = _base64ToBytes(
|
||||
device.signedPreKey.publicKey
|
||||
);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
device.signedPreKey.signature = _base64ToBytes(
|
||||
device.signedPreKey.signature
|
||||
);
|
||||
});
|
||||
return res;
|
||||
}).then(handleKeys);
|
||||
}
|
||||
|
||||
function getKeysForNumberUnauth(
|
||||
number,
|
||||
deviceId = '*',
|
||||
{ accessKey } = {}
|
||||
) {
|
||||
return _ajax({
|
||||
call: 'keys',
|
||||
httpType: 'GET',
|
||||
urlParameters: `/${number}/${deviceId}`,
|
||||
responseType: 'json',
|
||||
validateResponse: { identityKey: 'string', devices: 'object' },
|
||||
unauthenticated: true,
|
||||
accessKey,
|
||||
}).then(handleKeys);
|
||||
}
|
||||
|
||||
function sendMessagesUnauth(
|
||||
destination,
|
||||
messageArray,
|
||||
timestamp,
|
||||
silent,
|
||||
{ accessKey } = {}
|
||||
) {
|
||||
const jsonData = { messages: messageArray, timestamp };
|
||||
|
||||
if (silent) {
|
||||
jsonData.silent = true;
|
||||
}
|
||||
|
||||
return _ajax({
|
||||
call: 'messages',
|
||||
httpType: 'PUT',
|
||||
urlParameters: `/${destination}`,
|
||||
jsonData,
|
||||
responseType: 'json',
|
||||
unauthenticated: true,
|
||||
accessKey,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue