Merge pull request #1119 from AStove/Handshake

Use new authentication methods in weechat 2.9
codeql
Lorenz Hübschle-Schneider 5 years ago committed by GitHub
commit faccb8378e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      css/glowingbear.css
  2. 46
      index.html
  3. 284
      js/connection.js
  4. 10
      js/glowingbear.js
  5. 37
      js/utils.js
  6. 65
      js/weechat.js

@ -953,6 +953,10 @@ code {
border: 1pt solid #444; border: 1pt solid #444;
} }
.checkbox.indent {
margin-left: 20px;
}
#bufferlines.hideTime td.time { #bufferlines.hideTime td.time {
display:none; display:none;
} }

@ -71,6 +71,12 @@
<div class="alert alert-danger" ng-show="securityError" ng-cloak> <div class="alert alert-danger" ng-show="securityError" ng-cloak>
<strong>Secure connection error</strong> Unable to connect to unencrypted relay when you are connecting to Glowing Bear over HTTPS. Please use an encrypted relay or load the page without using HTTPS. <strong>Secure connection error</strong> Unable to connect to unencrypted relay when you are connecting to Glowing Bear over HTTPS. Please use an encrypted relay or load the page without using HTTPS.
</div> </div>
<div class="alert alert-danger" ng-show="oldWeechatError" ng-cloak>
<strong>Weechat version error</strong> Weechat connected but did not respond to a handshake. This could mean weechat < version 2.9. Verify your weechat is 2.8 or older and check "Compatibility with Weechat 2.8 and older" or consider updating weechat.
</div>
<div class="alert alert-danger" ng-show="hashAlgorithmDisagree" ng-cloak>
<strong>Hash algorithm error</strong> Weechat and glowing bear did not agree on a hashing algorithm, please do /set relay.network.password_hash_algo "pbkdf2+sha512" in weechat.
</div>
<div class="panel-group accordion"> <div class="panel-group accordion">
<div class="panel" data-state="active" ng-show=false> <div class="panel" data-state="active" ng-show=false>
<div class="panel-heading"> <div class="panel-heading">
@ -116,39 +122,42 @@
</div> </div>
</div> </div>
<div class="row no-gutter"> <div class="row no-gutter">
<div ng-class="settings.useTotp ? 'col-sm-9' : 'col-sm-12'" ng> <div class="col-sm-12">
<label class="control-label" for="password">WeeChat relay password</label> <label class="control-label" for="password">WeeChat relay password</label>
<input type="password" class="form-control favorite-font" id="password" ng-model="password" placeholder="Password"> <input type="password" class="form-control favorite-font" id="password" ng-model="password" placeholder="Password">
</div> </div>
<div class="col-sm-3" ng-Show="settings.useTotp">
<label class="control-label" for="totp">Token</label>
<input type="text" class="form-control favorite-font" id="totp" ng-model="totp" ng-change="parseTotp()" ng-class="{'is-invalid': totpInvalid}" autocomplete="off">
</div>
</div> </div>
<div class="alert alert-danger" ng-show="passwordError" ng-cloak> <div class="alert alert-danger" ng-show="passwordError" ng-cloak>
Error: wrong password or token Error: wrong password or token
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label class="control-label" for="savepassword"> <label class="control-label" for="ssl">
<input type="checkbox" id="savepassword" ng-model="settings.savepassword"> <input type="checkbox" id="ssl" ng-model="settings.ssl">
Save password in your browser Encryption. <strong>Strongly recommended!</strong> Need help? Check below.
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label class="control-label" for="compatibilityWeechat28">
<input type="checkbox" id="compatibilityWeechat28" ng-model="settings.compatibilityWeechat28">
Compatibility with Weechat 2.8 and older <a href="#plaintext" ng-click="toggleAccordionByName('gettingStartedAccordion')"><i class="glyphicon glyphicon-info-sign"></i></a>
<span style="color: #888;display:block">WeeChat 2.9 is scheduled for release in July 2020, so you&apos;ll likely want to keep this enabled for now.</span>
</label>
</div>
<div class="checkbox indent" ng-show="settings.compatibilityWeechat28">
<label class="control-label" for="useTotp"> <label class="control-label" for="useTotp">
<input type="checkbox" id="useTotp" ng-model="settings.useTotp"> <input type="checkbox" id="useTotp" ng-model="settings.useTotp">
Use Time-based One-Time Password <a href="https://blog.weechat.org/post/2019/01/14/Support-of-TOTP" target="_blank"><i class="glyphicon glyphicon-info-sign"></i></a> Use Time-based One-Time Password (automatic for Weechat >= 2.9)<a href="https://blog.weechat.org/post/2019/01/14/Support-of-TOTP" target="_blank"><i class="glyphicon glyphicon-info-sign"></i></a>
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label class="control-label" for="ssl"> <label class="control-label" for="savepassword">
<input type="checkbox" id="ssl" ng-model="settings.ssl"> <input type="checkbox" id="savepassword" ng-model="settings.savepassword">
Encryption. <strong>Strongly recommended!</strong> Need help? Check below. Save password in your browser
</label> </label>
</div> </div>
<div class="checkbox" ng-show="settings.savepassword || settings.autoconnect"> <div class="checkbox" ng-show="settings.savepassword || settings.autoconnect">
<label class="control-label" for="autoconnect"> <label class="control-label" for="autoconnect">
<input type="checkbox" id="autoconnect" ng-model="settings.autoconnect" ng-disabled="settings.useTotp"> <input type="checkbox" id="autoconnect" ng-model="settings.autoconnect" ng-disabled="settings.compatibilityWeechat28 && settings.useTotp">
Automatically connect Automatically connect
</label> </label>
</div> </div>
@ -158,7 +167,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="panel" data-state="collapsed"> <div class="panel" data-state="collapsed" id="gettingStartedAccordion">
<div class="panel-heading"> <div class="panel-heading">
<h4 class="panel-title"> <h4 class="panel-title">
<a class="accordion-toggle" ng-click="toggleAccordion($event)"> <a class="accordion-toggle" ng-click="toggleAccordion($event)">
@ -168,8 +177,8 @@
</div> </div>
<div id="collapseTwo" class="panel-collapse collapse"> <div id="collapseTwo" class="panel-collapse collapse">
<div class="panel-body"> <div class="panel-body">
<p><span class="label label-danger">WeeChat version 0.4.2 or higher is required, but WeeChat 2.9 or later is recommended for the best experience.</p>
<h3>Use TLS encryption</h3> <h3>Use TLS encryption</h3>
<p><span class="label label-danger">WeeChat version 0.4.2 or higher is required—we recommend at least 1.0.</p>
<p>To start using Glowing Bear, follow the instructions below to set up an encrypted relay. All communication goes directly between your browser and your WeeChat relay! This means that your server must be accessible. We never see any of your data or your password, and you don't need to trust a "cloud". All settings, including your password, are saved locally in your own browser between sessions.</p> <p>To start using Glowing Bear, follow the instructions below to set up an encrypted relay. All communication goes directly between your browser and your WeeChat relay! This means that your server must be accessible. We never see any of your data or your password, and you don't need to trust a "cloud". All settings, including your password, are saved locally in your own browser between sessions.</p>
<div class="alert alert-warning" ng-show="show_tls_warning"><strong>You're using Glowing Bear over an unencrypted connection (http://). This is not recommended!</strong> We recommend using our secure hosted version at <a href="https://www.glowing-bear.org/">https://www.glowing-bear.org/</a>, or <a href="https://latest.glowing-bear.org/">https://latest.glowing-bear.org</a> for the latest and greatest development version. You can still follow the instructions below to set up an encrypted relay, though.</div> <div class="alert alert-warning" ng-show="show_tls_warning"><strong>You're using Glowing Bear over an unencrypted connection (http://). This is not recommended!</strong> We recommend using our secure hosted version at <a href="https://www.glowing-bear.org/">https://www.glowing-bear.org/</a>, or <a href="https://latest.glowing-bear.org/">https://latest.glowing-bear.org</a> for the latest and greatest development version. You can still follow the instructions below to set up an encrypted relay, though.</div>
<p>When using encryption, all communication between your browser and WeeChat will be securely encrypted with TLS. This means that you have to set up a certificate. While it's possible to use a self-signed cert, we recommend against it, because it's handled poorly in browsers, and may not work at all on mobile devices. If you don't already have a certificate for your domain (or you don't have a domain), we strongly encourage you to get a certificate from <a href="https://letsencrypt.org/">Let's Encrypt</a>—it's free and easy. We'll walk you through it.</p> <p>When using encryption, all communication between your browser and WeeChat will be securely encrypted with TLS. This means that you have to set up a certificate. While it's possible to use a self-signed cert, we recommend against it, because it's handled poorly in browsers, and may not work at all on mobile devices. If you don't already have a certificate for your domain (or you don't have a domain), we strongly encourage you to get a certificate from <a href="https://letsencrypt.org/">Let's Encrypt</a>—it's free and easy. We'll walk you through it.</p>
@ -191,6 +200,13 @@ chown -R <strong>username</strong>:<strong>username</strong> ~<strong>username</
<pre>/secure set relay_totp_secret xxxxx <pre>/secure set relay_totp_secret xxxxx
/set relay.network.totp_secret "${sec.data.relay_totp_secret}"</pre> /set relay.network.totp_secret "${sec.data.relay_totp_secret}"</pre>
<p>Open an authenticator app and create an entry with the same secret. In Glowing Bear check the checkbox for "use Time-based One-Time Password" and fill in the one time password as you see it in the authenticator app.</p> <p>Open an authenticator app and create an entry with the same secret. In Glowing Bear check the checkbox for "use Time-based One-Time Password" and fill in the one time password as you see it in the authenticator app.</p>
<h3><a name="plaintext"></a>Compatibility with WeeChat 2.8 and older</h3>
<p><strong>Required for WeeChat <= 2.8</strong></p>
<p>With WeeChat 2.9—scheduled for release in July 2020—relay client authentication was made more secure and resistant to brute forcing. Glowing Bear uses the most secure authentication method by default. However, to support older versions of WeeChat, this option allows Glowing Bear to still use the old authentication method, sending your password to WeeChat (in plain text if you are not using encryption!). Only enable this if you are using a WeeChat version before 2.9!</p>
<p>By default, WeeChat 2.9 support several authentication methods. Of these, Glowing Bear only uses the most secure one, <code>pbkdf2+sha512</code>. You can check the list of enabled methods to ensure it is in there:
<code>/set relay.network.password_hash_algo</code>
</p>
</div> </div>
</div> </div>
</div> </div>

@ -4,12 +4,13 @@
var weechat = angular.module('weechat'); var weechat = angular.module('weechat');
weechat.factory('connection', weechat.factory('connection',
['$rootScope', '$log', 'handlers', 'models', 'settings', 'ngWebsockets', function($rootScope, ['$rootScope', '$log', 'handlers', 'models', 'settings', 'ngWebsockets', 'utils', function($rootScope,
$log, $log,
handlers, handlers,
models, models,
settings, settings,
ngWebsockets) { ngWebsockets,
utils) {
var protocol = new weeChat.Protocol(); var protocol = new weeChat.Protocol();
@ -22,6 +23,8 @@ weechat.factory('connection',
// Takes care of the connection and websocket hooks // Takes care of the connection and websocket hooks
var connect = function (host, port, path, passwd, ssl, useTotp, totp, noCompression, successCallback, failCallback) { var connect = function (host, port, path, passwd, ssl, useTotp, totp, noCompression, successCallback, failCallback) {
$rootScope.passwordError = false; $rootScope.passwordError = false;
$rootScope.oldWeechatError = false;
$rootScope.hashAlgorithmDisagree = false;
connectionData = [host, port, path, passwd, ssl, noCompression]; connectionData = [host, port, path, passwd, ssl, noCompression];
var proto = ssl ? 'wss' : 'ws'; var proto = ssl ? 'wss' : 'ws';
// If host is an IPv6 literal wrap it in brackets // If host is an IPv6 literal wrap it in brackets
@ -31,31 +34,124 @@ weechat.factory('connection',
var url = proto + "://" + host + ":" + port + "/" + path; var url = proto + "://" + host + ":" + port + "/" + path;
$log.debug('Connecting to URL: ', url); $log.debug('Connecting to URL: ', url);
var weechatAssumedPre2_9 = false;
var onopen = function () { var onopen = function () {
var _performHandshake = function() {
return new Promise(function(resolve) {
// First a handshake is sent to determine authentication method
// This is only supported for weechat >= 2.9
// If after 'a while' weechat does not respond
// stop waiting for the handshake and assume it's an old version
// This time is debatable, high latency connections may wrongfully
// think weechat is an older version. This time is purposfully set
// too high, this time should be reduced if determined the weechat
// is lower than 2.9
// This time also includes the time it takes to generate the hash
const WAIT_TIME_OLD_WEECHAT = 200; //ms
// Wait long enough to assume we are on a version < 2.9
var handShakeTimeout = setTimeout(function () {
weechatAssumedPre2_9 = true;
console.log('Weechat\'s version is assumed to be < 2.9');
resolve();
}, WAIT_TIME_OLD_WEECHAT);
// Or wait for a response from the handshake
ngWebsockets.send(
weeChat.Protocol.formatHandshake({
password_hash_algo: "pbkdf2+sha512", compression: noCompression ? 'off' : 'zlib'
})
).then(function (message){
clearTimeout(handShakeTimeout);
resolve(message);
});
});
};
var _askTotp = function (useTotp) {
return new Promise(function(resolve) {
// If weechat is < 2.9 the totp will be a setting (checkbox)
// Otherwise the handshake will specify it
if (useTotp) {
// Ask the user to input his TOTP
var totp = prompt("Please enter your TOTP Token");
resolve(totp);
} else {
// User does not use TOTP, don't ask
resolve(null);
}
});
};
// Helper methods for initialization commands // Helper methods for initialization commands
var _initializeConnection = function(passwd) { // This method is used to initialize weechat < 2.9
var _initializeConnectionPre29 = function(passwd, totp) {
// This is not secure, this has to be specifically allowed with a setting
// Otherwise an attacker could persuade the client to send it's password
// Or due to latency the client could think weechat was an older version
if (!settings.compatibilityWeechat28) {
$rootScope.oldWeechatError = true;
$rootScope.$emit('relayDisconnect');
$rootScope.$digest(); // Have to do this otherwise change detection doesn't see the error.
throw new Error('Plaintext authentication not allowed.');
}
// Escape comma in password (#937) // Escape comma in password (#937)
passwd = passwd.replace(',', '\\,'); passwd = passwd.replace(',', '\\,');
// This is not the proper way to do this.
// WeeChat does not send a confirmation for the init.
// Until it does, We need to "assume" that formatInit
// will be received before formatInfo
ngWebsockets.send( ngWebsockets.send(
weeChat.Protocol.formatInit({ weeChat.Protocol.formatInitPre29({
password: passwd, password: passwd,
compression: noCompression ? 'off' : 'zlib', compression: noCompression ? 'off' : 'zlib',
useTotp: useTotp,
totp: totp totp: totp
}) })
); );
return ngWebsockets.send( // Wait a little bit until the init is sent
weeChat.Protocol.formatInfo({ return new Promise(function(resolve) {
name: 'version' setTimeout(function() { resolve(); }, 5);
}) });
);
};
// Helper methods for initialization commands
// This method is used to initialize weechat >= 2.9
var salt;
var _initializeConnection29 = function(passwd, nonce, iterations, totp) {
return window.crypto.subtle.importKey(
'raw',
utils.stringToUTF8Array(passwd),
{name: 'PBKDF2'},//{name: 'HMAC', hash: 'SHA-512'},
false,
['deriveBits']
).then(function (key) {
var clientnonce = window.crypto.getRandomValues(new Uint8Array(16));
//nonce:clientnonce, 3A is a ':' in ASCII
salt = utils.concatenateTypedArrays(
nonce, new Uint8Array([0x3A]), clientnonce);
return window.crypto.subtle.deriveBits(
{
name: 'PBKDF2',
hash: 'SHA-512',
salt: salt,
iterations: iterations,
}, key, 512
);
}).then(function (hash) {
ngWebsockets.send(
weeChat.Protocol.formatInit29(
'pbkdf2+sha512:' + utils.bytetoHexString(salt) + ':' +
iterations + ':' + utils.bytetoHexString(hash),
totp
)
);
// Wait a little bit until the init is sent
return new Promise(function(resolve) {
setTimeout(function() { resolve(); }, 5);
});
});
}; };
var _requestHotlist = function() { var _requestHotlist = function() {
@ -180,71 +276,114 @@ weechat.factory('connection',
$rootScope.angularTimeFormat = angularFormat; $rootScope.angularTimeFormat = angularFormat;
}; };
var passwordMethod;
// First command asks for the password and issues var totpRequested;
// a version command. If it fails, it means the we var nonce;
// did not provide the proper password. var iterations;
_initializeConnection(passwd).then(
function(version) { _performHandshake().then(
handlers.handleVersionInfo(version); // Wait for weechat to respond or handshake times out
// Connection is successful function (message) {
// Send all the other commands required for initialization // Do nothing if the handshake was received
_requestBufferInfos().then(function(bufinfo) { // after concluding weechat was an old version
handlers.handleBufferInfo(bufinfo); // TODO maybe warn the user here
}); if (weechatAssumedPre2_9) {
return;
_requestHotlist().then(function(hotlist) {
handlers.handleHotlistInfo(hotlist);
});
if (settings.hotlistsync) {
// Schedule hotlist syncing every so often so that this
// client will have unread counts (mostly) in sync with
// other clients or terminal usage directly.
setInterval(function() {
if ($rootScope.connected) {
_requestHotlist().then(function(hotlist) {
handlers.handleHotlistInfo(hotlist);
});
}
}, 60000); // Sync hotlist every 60 second
} }
var content = message.objects[0].content;
// Fetch weechat time format for displaying timestamps passwordMethod = content.password_hash_algo;
fetchConfValue('weechat.look.buffer_time_format', totpRequested = (content.totp === 'on');
function() { nonce = utils.hexStringToByte(content.nonce);
// Will set models.wconfig['weechat.look.buffer_time_format'] iterations = content.password_hash_iterations;
_parseWeechatTimeFormat();
if (passwordMethod != "pbkdf2+sha512") {
$rootScope.hashAlgorithmDisagree = true;
$rootScope.$emit('relayDisconnect');
$rootScope.$digest(); // Have to do this otherwise change detection doesn't see the error.
throw new Error('No supported password hash algorithm returned.');
}
}
).then(function() {
if (weechatAssumedPre2_9) {
// Ask the user for the TOTP token if this is enabled
return _askTotp(useTotp)
.then(function (totp) {
return _initializeConnectionPre29(passwd, totp);
}); });
} else {
// Weechat version >= 2.9
return _askTotp(totpRequested)
.then(function(totp) {
return _initializeConnection29(passwd, nonce, iterations, totp);
});
}
}).then(function(){
// The Init was sent, weechat will not respond
// Wait until either the connection closes
// Or try to send version and see if weechat responds
return ngWebsockets.send(
weeChat.Protocol.formatInfo({
name: 'version'
})
);
}).then(function(version) {
// From now on we are assumed initialized
// We don't know for sure because weechat does not respond
// All we know is the socket wasn't closed afer waiting a little bit
console.log('Succesfully connected');
$rootScope.waseverconnected = true;
handlers.handleVersionInfo(version);
// Send all the other commands required for initialization
_requestBufferInfos().then(function(bufinfo) {
handlers.handleBufferInfo(bufinfo);
});
_requestHotlist().then(function(hotlist) {
handlers.handleHotlistInfo(hotlist);
});
if (settings.hotlistsync) {
// Schedule hotlist syncing every so often so that this
// client will have unread counts (mostly) in sync with
// other clients or terminal usage directly.
setInterval(function() {
if ($rootScope.connected) {
_requestHotlist().then(function(hotlist) {
handlers.handleHotlistInfo(hotlist);
});
}
}, 60000); // Sync hotlist every 60 second
}
// Fetch nick completion config // Fetch weechat time format for displaying timestamps
fetchConfValue('weechat.completion.nick_completer'); fetchConfValue('weechat.look.buffer_time_format',
fetchConfValue('weechat.completion.nick_add_space'); function() {
// Will set models.wconfig['weechat.look.buffer_time_format']
_requestSync(); _parseWeechatTimeFormat();
$log.info("Connected to relay"); });
$rootScope.connected = true;
if (successCallback) { // Fetch nick completion config
successCallback(); fetchConfValue('weechat.completion.nick_completer');
} fetchConfValue('weechat.completion.nick_add_space');
},
function() { _requestSync();
handleWrongPassword(); $log.info("Connected to relay");
$rootScope.connected = true;
if (successCallback) {
successCallback();
} }
);
}; },
var onmessage = function() { //Sending version failed
// If we recieve a message from WeeChat it means that function() {
// password was OK. Store that result and check for it handleWrongPassword();
// in the failure handler. });
$rootScope.waseverconnected = true;
}; };
var onclose = function (evt) { var onclose = function (evt) {
/* /*
* Handles websocket disconnection * Handles websocket disconnection
@ -274,7 +413,9 @@ weechat.factory('connection',
var handleWrongPassword = function() { var handleWrongPassword = function() {
// Connection got closed, lets check if we ever was connected successfully // Connection got closed, lets check if we ever was connected successfully
if (!$rootScope.waseverconnected && !$rootScope.errorMessage) { if (!$rootScope.waseverconnected && !$rootScope.errorMessage &&
!$rootScope.oldWeechatError && !$rootScope.hashAlgorithmDisagree)
{
$rootScope.passwordError = true; $rootScope.passwordError = true;
$rootScope.$apply(); $rootScope.$apply();
} }
@ -309,7 +450,6 @@ weechat.factory('connection',
'binaryType': "arraybuffer", 'binaryType': "arraybuffer",
'onopen': onopen, 'onopen': onopen,
'onclose': onclose, 'onclose': onclose,
'onmessage': onmessage,
'onerror': onerror 'onerror': onerror
}); });
} catch(e) { } catch(e) {

@ -45,6 +45,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
'port': 9001, 'port': 9001,
'path': 'weechat', 'path': 'weechat',
'ssl': (window.location.protocol === "https:"), 'ssl': (window.location.protocol === "https:"),
'compatibilityWeechat28': true,
'useTotp': false, 'useTotp': false,
'savepassword': false, 'savepassword': false,
'autoconnect': false, 'autoconnect': false,
@ -764,6 +765,15 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
event.preventDefault(); event.preventDefault();
var target = event.target.parentNode.parentNode.parentNode; var target = event.target.parentNode.parentNode.parentNode;
toggleAccordionByTarget(target);
};
$scope.toggleAccordionByName = function(name) {
var target = document.getElementById(name);
toggleAccordionByTarget(target);
};
var toggleAccordionByTarget = function(target) {
target.setAttribute('data-state', target.getAttribute('data-state') === 'active' ? 'collapsed' : 'active'); target.setAttribute('data-state', target.getAttribute('data-state') === 'active' ? 'collapsed' : 'active');
// Hide all other siblings // Hide all other siblings

@ -45,6 +45,39 @@ weechat.factory('utils', function() {
head.appendChild(elem); head.appendChild(elem);
}; };
// Convert string to ByteArray
function hexStringToByte(str) {
if (!str) {
return new Uint8Array();
}
var a = [];
for (var i = 0, len = str.length; i < len; i+=2) {
a.push(parseInt(str.substr(i, 2), 16));
}
return new Uint8Array(a);
}
function bytetoHexString(buffer) {
return Array
.from(new Uint8Array (buffer))
.map(function(b) { return b.toString(16).padStart(2, "0"); })
.join("");
}
function stringToUTF8Array(string) {
return new TextEncoder().encode(string);
}
// Concatenate three TypedArrays of the same type
function concatenateTypedArrays(a, b, c) {
var res = new (a.constructor)(a.length + b.length + c.length);
res.set(a, 0);
res.set(b, a.length);
res.set(c, a.length + b.length);
return res;
}
return { return {
changeClassStyle: changeClassStyle, changeClassStyle: changeClassStyle,
@ -53,5 +86,9 @@ weechat.factory('utils', function() {
isCordova: isCordova, isCordova: isCordova,
inject_script: inject_script, inject_script: inject_script,
inject_css: inject_css, inject_css: inject_css,
hexStringToByte: hexStringToByte,
bytetoHexString: bytetoHexString,
stringToUTF8Array: stringToUTF8Array,
concatenateTypedArrays: concatenateTypedArrays
}; };
}); });

@ -628,17 +628,51 @@
}; };
/** /**
* Formats an init command. * Formats a handshake command.
*
* @param params Parameters:
* password: list of supported hash algorithms, colon separated (optional)
* compression: compression ('off' or 'zlib') (optional)
* @return Formatted handshake command string
*/
//https://weechat.org/files/doc/stable/weechat_relay_protocol.en.html#command_handshake
WeeChatProtocol.formatHandshake = function(params) {
var defaultParams = {
password_hash_algo: 'pbkdf2+sha512',
compression: 'zlib'
};
var keys = [];
var parts = [];
params = WeeChatProtocol._mergeParams(defaultParams, params);
if (params.compression !== null) {
keys.push('compression=' + params.compression);
}
if (params.password_hash_algo !== null) {
keys.push('password_hash_algo=' + params.password_hash_algo);
}
parts.push(keys.join(','));
return WeeChatProtocol._formatCmd(null, 'handshake', parts);
};
/**
* Formats an init command for weechat versions < 2.9
* *
* @param params Parameters: * @param params Parameters:
* password: password (optional) * password: password (optional)
* compression: compression ('off' or 'zlib') (optional) * compression: compression ('off' or 'zlib') (optional)
* totp: One Time Password (optional)
* @return Formatted init command string * @return Formatted init command string
*/ */
WeeChatProtocol.formatInit = function(params) { WeeChatProtocol.formatInitPre29 = function(params) {
var defaultParams = { var defaultParams = {
password: null, password: null,
compression: 'zlib' compression: 'zlib',
totp: null
}; };
var keys = []; var keys = [];
var parts = []; var parts = [];
@ -648,7 +682,7 @@
if (params.password !== null) { if (params.password !== null) {
keys.push('password=' + params.password); keys.push('password=' + params.password);
} }
if (params.useTotp) { if (params.totp !== null) {
keys.push('totp=' + params.totp); keys.push('totp=' + params.totp);
} }
parts.push(keys.join(',')); parts.push(keys.join(','));
@ -656,6 +690,29 @@
return WeeChatProtocol._formatCmd(null, 'init', parts); return WeeChatProtocol._formatCmd(null, 'init', parts);
}; };
/**
* Formats an init command for weechat versions >= 2.9
*
* @param params Parameters:
* password_hash: hash of password with method and salt
* totp: One Time Password (can be null)
* @return Formatted init command string
*/
WeeChatProtocol.formatInit29 = function(password_hash, totp) {
var keys = [];
var parts = [];
if (totp != null) {
keys.push('totp=' + totp);
}
if (password_hash !== null) {
keys.push('password_hash=' + password_hash);
}
parts.push(keys.join(','));
return WeeChatProtocol._formatCmd(null, 'init', parts);
};
/** /**
* Formats an hdata command. * Formats an hdata command.
* *

Loading…
Cancel
Save