Change the authentication workflow. This will allow Sshwifty to run on a multi-node autobalanced cluster. After deploy this version, users might have to reload the frontend page before continue using Sshwifty.
This commit is contained in:
@@ -23,7 +23,6 @@ import (
|
|||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -66,32 +65,14 @@ type socket struct {
|
|||||||
|
|
||||||
commonCfg configuration.Common
|
commonCfg configuration.Common
|
||||||
serverCfg configuration.Server
|
serverCfg configuration.Server
|
||||||
randomKey string
|
|
||||||
authKey []byte
|
|
||||||
upgrader websocket.Upgrader
|
upgrader websocket.Upgrader
|
||||||
commander command.Commander
|
commander command.Commander
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNewSocketCtlRandomSharedKey() string {
|
func hashCombineSocketKeys(addedKey string, privateKey string) []byte {
|
||||||
b := [32]byte{}
|
h := hmac.New(sha512.New, []byte(privateKey))
|
||||||
|
|
||||||
io.ReadFull(rand.Reader, b[:])
|
h.Write([]byte(addedKey))
|
||||||
|
|
||||||
return base64.StdEncoding.EncodeToString(b[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSocketAuthKey(randomKey string, sharedKey string) []byte {
|
|
||||||
var k []byte
|
|
||||||
|
|
||||||
if len(sharedKey) > 0 {
|
|
||||||
k = []byte(sharedKey)
|
|
||||||
} else {
|
|
||||||
k = []byte(randomKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
h := hmac.New(sha512.New, k)
|
|
||||||
|
|
||||||
h.Write([]byte(randomKey))
|
|
||||||
|
|
||||||
return h.Sum(nil)
|
return h.Sum(nil)
|
||||||
}
|
}
|
||||||
@@ -101,13 +82,9 @@ func newSocketCtl(
|
|||||||
cfg configuration.Server,
|
cfg configuration.Server,
|
||||||
cmds command.Commands,
|
cmds command.Commands,
|
||||||
) socket {
|
) socket {
|
||||||
randomKey := getNewSocketCtlRandomSharedKey()
|
|
||||||
|
|
||||||
return socket{
|
return socket{
|
||||||
commonCfg: commonCfg,
|
commonCfg: commonCfg,
|
||||||
serverCfg: cfg,
|
serverCfg: cfg,
|
||||||
randomKey: randomKey,
|
|
||||||
authKey: getSocketAuthKey(randomKey, commonCfg.SharedKey)[:32],
|
|
||||||
upgrader: buildWebsocketUpgrader(cfg),
|
upgrader: buildWebsocketUpgrader(cfg),
|
||||||
commander: command.New(cmds),
|
commander: command.New(cmds),
|
||||||
}
|
}
|
||||||
@@ -234,19 +211,18 @@ func (s socket) createCipher(key []byte) (cipher.AEAD, cipher.AEAD, error) {
|
|||||||
return gcmRead, gcmWrite, nil
|
return gcmRead, gcmWrite, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s socket) privateKey() string {
|
func (s socket) mixerKey(r *http.Request) []byte {
|
||||||
if len(s.commonCfg.SharedKey) > 0 {
|
return hashCombineSocketKeys(
|
||||||
return s.commonCfg.SharedKey
|
r.UserAgent(), s.commonCfg.SharedKey+"+"+s.commonCfg.HostName)
|
||||||
}
|
|
||||||
|
|
||||||
return s.randomKey
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s socket) buildCipherKey() [16]byte {
|
func (s socket) buildCipherKey(r *http.Request) [16]byte {
|
||||||
key := [16]byte{}
|
key := [16]byte{}
|
||||||
now := strconv.FormatInt(time.Now().Unix()/100, 10)
|
|
||||||
|
|
||||||
copy(key[:], getSocketAuthKey(now, s.privateKey()))
|
copy(key[:], hashCombineSocketKeys(
|
||||||
|
strconv.FormatInt(time.Now().Unix()/100, 10),
|
||||||
|
string(s.mixerKey(r))+"+"+s.commonCfg.SharedKey,
|
||||||
|
))
|
||||||
|
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
@@ -300,7 +276,7 @@ func (s socket) Get(
|
|||||||
"Unable to send server nonce to client: %s", nonceSendErr.Error()))
|
"Unable to send server nonce to client: %s", nonceSendErr.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
cipherKey := s.buildCipherKey()
|
cipherKey := s.buildCipherKey(r)
|
||||||
|
|
||||||
readCipher, writeCipher, cipherCreationErr := s.createCipher(cipherKey[:])
|
readCipher, writeCipher, cipherCreationErr := s.createCipher(cipherKey[:])
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,22 @@ func newSocketVerification(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s socketVerification) authKey(r *http.Request) []byte {
|
||||||
|
timeMixer := strconv.FormatInt(time.Now().Unix()/100, 10)
|
||||||
|
|
||||||
|
if len(s.commonCfg.SharedKey) > 0 {
|
||||||
|
return hashCombineSocketKeys(
|
||||||
|
timeMixer,
|
||||||
|
s.commonCfg.SharedKey,
|
||||||
|
)[:32]
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashCombineSocketKeys(
|
||||||
|
timeMixer,
|
||||||
|
"DEFAULT VERIFY KEY",
|
||||||
|
)[:32]
|
||||||
|
}
|
||||||
|
|
||||||
func (s socketVerification) setServerConfigRespond(
|
func (s socketVerification) setServerConfigRespond(
|
||||||
hd *http.Header, w http.ResponseWriter) {
|
hd *http.Header, w http.ResponseWriter) {
|
||||||
hd.Add("X-Heartbeat", s.heartbeat)
|
hd.Add("X-Heartbeat", s.heartbeat)
|
||||||
@@ -104,7 +120,7 @@ func (s socketVerification) Get(
|
|||||||
key := r.Header.Get("X-Key")
|
key := r.Header.Get("X-Key")
|
||||||
|
|
||||||
if len(key) <= 0 {
|
if len(key) <= 0 {
|
||||||
hd.Add("X-Key", s.randomKey)
|
hd.Add("X-Key", base64.StdEncoding.EncodeToString(s.mixerKey(r)))
|
||||||
|
|
||||||
if len(s.commonCfg.SharedKey) <= 0 {
|
if len(s.commonCfg.SharedKey) <= 0 {
|
||||||
s.setServerConfigRespond(&hd, w)
|
s.setServerConfigRespond(&hd, w)
|
||||||
@@ -129,11 +145,13 @@ func (s socketVerification) Get(
|
|||||||
return NewError(http.StatusBadRequest, decodedKeyErr.Error())
|
return NewError(http.StatusBadRequest, decodedKeyErr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hmac.Equal(s.authKey, decodedKey) {
|
authKey := s.authKey(r)
|
||||||
|
|
||||||
|
if !hmac.Equal(authKey, decodedKey) {
|
||||||
return ErrSocketAuthFailed
|
return ErrSocketAuthFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
hd.Add("X-Key", s.randomKey)
|
hd.Add("X-Key", base64.StdEncoding.EncodeToString(s.mixerKey(r)))
|
||||||
s.setServerConfigRespond(&hd, w)
|
s.setServerConfigRespond(&hd, w)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
129
ui/app.js
129
ui/app.js
@@ -32,6 +32,7 @@ import Home from "./home.vue";
|
|||||||
import "./landing.css";
|
import "./landing.css";
|
||||||
import Loading from "./loading.vue";
|
import Loading from "./loading.vue";
|
||||||
import { Socket } from "./socket.js";
|
import { Socket } from "./socket.js";
|
||||||
|
import * as stream from "./stream/common";
|
||||||
import * as xhr from "./xhr.js";
|
import * as xhr from "./xhr.js";
|
||||||
|
|
||||||
const backendQueryRetryDelay = 2000;
|
const backendQueryRetryDelay = 2000;
|
||||||
@@ -72,6 +73,19 @@ function startApp(rootEl) {
|
|||||||
|
|
||||||
let uiControlColor = new ControlColor();
|
let uiControlColor = new ControlColor();
|
||||||
|
|
||||||
|
function getCurrentKeyMixer() {
|
||||||
|
return Number(Math.trunc(new Date().getTime() / 100000)).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildSocketKey(privateKey) {
|
||||||
|
return new Uint8Array(
|
||||||
|
await cipher.hmac512(
|
||||||
|
stream.buildBufferFromString(privateKey),
|
||||||
|
stream.buildBufferFromString(getCurrentKeyMixer())
|
||||||
|
)
|
||||||
|
).slice(0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: rootEl,
|
el: rootEl,
|
||||||
components: {
|
components: {
|
||||||
@@ -170,11 +184,20 @@ function startApp(rootEl) {
|
|||||||
isErrored() {
|
isErrored() {
|
||||||
return this.authErr.length > 0 || this.loadErr.length > 0;
|
return this.authErr.length > 0 || this.loadErr.length > 0;
|
||||||
},
|
},
|
||||||
async getSocketAuthKey(privateKey, randomKey) {
|
async getSocketAuthKey(privateKey) {
|
||||||
const enc = new TextEncoder();
|
const enc = new TextEncoder(),
|
||||||
|
rTime = Number(Math.trunc(new Date().getTime() / 100000));
|
||||||
|
|
||||||
|
var finalKey = "";
|
||||||
|
|
||||||
|
if (privateKey.length <= 0) {
|
||||||
|
finalKey = "DEFAULT VERIFY KEY";
|
||||||
|
} else {
|
||||||
|
finalKey = privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
return new Uint8Array(
|
return new Uint8Array(
|
||||||
await cipher.hmac512(enc.encode(privateKey), enc.encode(randomKey))
|
await cipher.hmac512(enc.encode(finalKey), enc.encode(rTime))
|
||||||
).slice(0, 32);
|
).slice(0, 32);
|
||||||
},
|
},
|
||||||
buildBackendSocketURL() {
|
buildBackendSocketURL() {
|
||||||
@@ -213,6 +236,40 @@ function startApp(rootEl) {
|
|||||||
);
|
);
|
||||||
this.page = "app";
|
this.page = "app";
|
||||||
},
|
},
|
||||||
|
async doAuth(privateKey) {
|
||||||
|
let result = await this.requestAuth(privateKey);
|
||||||
|
|
||||||
|
if (result.key) {
|
||||||
|
this.key = result.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
async requestAuth(privateKey) {
|
||||||
|
let authKey =
|
||||||
|
!privateKey || !this.key
|
||||||
|
? null
|
||||||
|
: await this.getSocketAuthKey(privateKey);
|
||||||
|
|
||||||
|
let h = await xhr.get(socksVerificationInterface, {
|
||||||
|
"X-Key": authKey
|
||||||
|
? btoa(String.fromCharCode.apply(null, authKey))
|
||||||
|
: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
let serverDate = h.getResponseHeader("Date");
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: h.status,
|
||||||
|
key: h.getResponseHeader("X-Key"),
|
||||||
|
timeout: h.getResponseHeader("X-Timeout"),
|
||||||
|
heartbeat: h.getResponseHeader("X-Heartbeat"),
|
||||||
|
date: serverDate ? new Date(serverDate) : null,
|
||||||
|
data: h.responseText,
|
||||||
|
onlyAllowPresetRemotes:
|
||||||
|
h.getResponseHeader("X-OnlyAllowPresetRemotes") === "yes",
|
||||||
|
};
|
||||||
|
},
|
||||||
async tryInitialAuth() {
|
async tryInitialAuth() {
|
||||||
try {
|
try {
|
||||||
let result = await this.doAuth("");
|
let result = await this.doAuth("");
|
||||||
@@ -235,17 +292,14 @@ function startApp(rootEl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
switch (result.result) {
|
switch (result.result) {
|
||||||
case 200:
|
case 200:
|
||||||
this.executeHomeApp(result, {
|
this.executeHomeApp(result, {
|
||||||
data: result.key,
|
data: await buildSocketKey(atob(result.key) + "+"),
|
||||||
async fetch() {
|
async fetch() {
|
||||||
if (this.data) {
|
if (this.data) {
|
||||||
let dKey = this.data;
|
let dKey = this.data;
|
||||||
|
|
||||||
this.data = null;
|
this.data = null;
|
||||||
|
|
||||||
return dKey;
|
return dKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +313,7 @@ function startApp(rootEl) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.key;
|
return await buildSocketKey(atob(result.key) + "+");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -281,52 +335,37 @@ function startApp(rootEl) {
|
|||||||
this.loadErr = "Unable to initialize client application: " + e;
|
this.loadErr = "Unable to initialize client application: " + e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async doAuth(privateKey) {
|
|
||||||
let result = await this.requestAuth(privateKey);
|
|
||||||
|
|
||||||
if (result.key) {
|
|
||||||
this.key = result.key;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
async requestAuth(privateKey) {
|
|
||||||
let authKey =
|
|
||||||
!privateKey || !this.key
|
|
||||||
? null
|
|
||||||
: await this.getSocketAuthKey(privateKey, this.key);
|
|
||||||
|
|
||||||
let h = await xhr.get(socksVerificationInterface, {
|
|
||||||
"X-Key": authKey
|
|
||||||
? btoa(String.fromCharCode.apply(null, authKey))
|
|
||||||
: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
let serverDate = h.getResponseHeader("Date");
|
|
||||||
|
|
||||||
return {
|
|
||||||
result: h.status,
|
|
||||||
key: h.getResponseHeader("X-Key"),
|
|
||||||
timeout: h.getResponseHeader("X-Timeout"),
|
|
||||||
heartbeat: h.getResponseHeader("X-Heartbeat"),
|
|
||||||
date: serverDate ? new Date(serverDate) : null,
|
|
||||||
data: h.responseText,
|
|
||||||
onlyAllowPresetRemotes:
|
|
||||||
h.getResponseHeader("X-OnlyAllowPresetRemotes") === "yes",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async submitAuth(passphrase) {
|
async submitAuth(passphrase) {
|
||||||
this.authErr = "";
|
this.authErr = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let result = await this.doAuth(passphrase);
|
let result = await this.doAuth(passphrase);
|
||||||
|
|
||||||
|
let self = this;
|
||||||
switch (result.result) {
|
switch (result.result) {
|
||||||
case 200:
|
case 200:
|
||||||
this.executeHomeApp(result, {
|
this.executeHomeApp(result, {
|
||||||
data: passphrase,
|
data: await buildSocketKey(atob(result.key) + "+" + passphrase),
|
||||||
fetch() {
|
async fetch() {
|
||||||
return this.data;
|
if (this.data) {
|
||||||
|
let dKey = this.data;
|
||||||
|
this.data = null;
|
||||||
|
return dKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = await self.doAuth(passphrase);
|
||||||
|
|
||||||
|
if (result.result !== 200) {
|
||||||
|
throw new Error(
|
||||||
|
"Unable to fetch key from remote, unexpected " +
|
||||||
|
"error code: " +
|
||||||
|
result.result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await buildSocketKey(
|
||||||
|
atob(result.key) + "+" + passphrase
|
||||||
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export async function hmac512(secret, data) {
|
|||||||
secret,
|
secret,
|
||||||
{
|
{
|
||||||
name: "HMAC",
|
name: "HMAC",
|
||||||
hash: { name: "SHA-512" }
|
hash: { name: "SHA-512" },
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
["sign", "verify"]
|
["sign", "verify"]
|
||||||
@@ -50,7 +50,7 @@ export function buildGCMKey(keyData) {
|
|||||||
keyData,
|
keyData,
|
||||||
{
|
{
|
||||||
name: "AES-GCM",
|
name: "AES-GCM",
|
||||||
length: GCMKeyBitLen
|
length: GCMKeyBitLen,
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
["encrypt", "decrypt"]
|
["encrypt", "decrypt"]
|
||||||
|
|||||||
65
ui/socket.js
65
ui/socket.js
@@ -15,10 +15,10 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import * as streams from "./stream/streams.js";
|
import * as crypt from "./crypto.js";
|
||||||
import * as reader from "./stream/reader.js";
|
import * as reader from "./stream/reader.js";
|
||||||
import * as sender from "./stream/sender.js";
|
import * as sender from "./stream/sender.js";
|
||||||
import * as crypt from "./crypto.js";
|
import * as streams from "./stream/streams.js";
|
||||||
|
|
||||||
export const ECHO_FAILED = streams.ECHO_FAILED;
|
export const ECHO_FAILED = streams.ECHO_FAILED;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class Dial {
|
|||||||
timeoutTimer = setTimeout(() => {
|
timeoutTimer = setTimeout(() => {
|
||||||
ws.close();
|
ws.close();
|
||||||
}, timeout),
|
}, timeout),
|
||||||
myRes = w => {
|
myRes = (w) => {
|
||||||
if (promised) {
|
if (promised) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ class Dial {
|
|||||||
|
|
||||||
return resolve(w);
|
return resolve(w);
|
||||||
},
|
},
|
||||||
myRej = e => {
|
myRej = (e) => {
|
||||||
if (promised) {
|
if (promised) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -77,11 +77,11 @@ class Dial {
|
|||||||
return reject(e);
|
return reject(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.addEventListener("open", _event => {
|
ws.addEventListener("open", (_event) => {
|
||||||
myRes(ws);
|
myRes(ws);
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.addEventListener("close", event => {
|
ws.addEventListener("close", (event) => {
|
||||||
event.toString = () => {
|
event.toString = () => {
|
||||||
return "WebSocket Error (" + event.code + ")";
|
return "WebSocket Error (" + event.code + ")";
|
||||||
};
|
};
|
||||||
@@ -89,7 +89,7 @@ class Dial {
|
|||||||
myRej(event);
|
myRej(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.addEventListener("error", _event => {
|
ws.addEventListener("error", (_event) => {
|
||||||
ws.close();
|
ws.close();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -100,15 +100,7 @@ class Dial {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
async buildKeyString() {
|
async buildKeyString() {
|
||||||
const enc = new TextEncoder();
|
return this.privateKey.fetch();
|
||||||
|
|
||||||
let rTime = Number(Math.trunc(new Date().getTime() / 100000)),
|
|
||||||
key = await crypt.hmac512(
|
|
||||||
enc.encode(await this.privateKey.fetch()),
|
|
||||||
enc.encode(rTime)
|
|
||||||
);
|
|
||||||
|
|
||||||
return key.slice(0, 16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,12 +123,14 @@ class Dial {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
async dial(callbacks) {
|
async dial(callbacks) {
|
||||||
let ws = await this.connect(this.timeout),
|
let ws = await this.connect(this.timeout);
|
||||||
rd = new reader.Reader(new reader.Multiple(() => {}), data => {
|
|
||||||
return new Promise(resolve => {
|
try {
|
||||||
|
let rd = new reader.Reader(new reader.Multiple(() => {}), (data) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
let bufferReader = new FileReader();
|
let bufferReader = new FileReader();
|
||||||
|
|
||||||
bufferReader.onload = event => {
|
bufferReader.onload = (event) => {
|
||||||
let d = new Uint8Array(event.target.result);
|
let d = new Uint8Array(event.target.result);
|
||||||
|
|
||||||
resolve(d);
|
resolve(d);
|
||||||
@@ -148,13 +142,13 @@ class Dial {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.addEventListener("message", event => {
|
ws.addEventListener("message", (event) => {
|
||||||
callbacks.inbound(event.data);
|
callbacks.inbound(event.data);
|
||||||
|
|
||||||
rd.feed(event.data);
|
rd.feed(event.data);
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.addEventListener("error", event => {
|
ws.addEventListener("error", (event) => {
|
||||||
event.toString = () => {
|
event.toString = () => {
|
||||||
return (
|
return (
|
||||||
"WebSocket Error (" + (event.code ? event.code : "Unknown") + ")"
|
"WebSocket Error (" + (event.code ? event.code : "Unknown") + ")"
|
||||||
@@ -164,18 +158,18 @@ class Dial {
|
|||||||
rd.closeWithReason(event);
|
rd.closeWithReason(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.addEventListener("close", _event => {
|
ws.addEventListener("close", (_event) => {
|
||||||
rd.closeWithReason("Connection is closed");
|
rd.closeWithReason("Connection is closed");
|
||||||
});
|
});
|
||||||
|
|
||||||
let sdDataConvert = rawData => {
|
let sdDataConvert = (rawData) => {
|
||||||
return rawData;
|
return rawData;
|
||||||
},
|
},
|
||||||
getSdDataConvert = () => {
|
getSdDataConvert = () => {
|
||||||
return sdDataConvert;
|
return sdDataConvert;
|
||||||
},
|
},
|
||||||
sd = new sender.Sender(
|
sd = new sender.Sender(
|
||||||
async rawData => {
|
async (rawData) => {
|
||||||
try {
|
try {
|
||||||
let data = await getSdDataConvert()(rawData);
|
let data = await getSdDataConvert()(rawData);
|
||||||
|
|
||||||
@@ -204,7 +198,7 @@ class Dial {
|
|||||||
|
|
||||||
let key = await this.buildKey();
|
let key = await this.buildKey();
|
||||||
|
|
||||||
sdDataConvert = async rawData => {
|
sdDataConvert = async (rawData) => {
|
||||||
let encoded = await crypt.encryptGCM(key, senderNonce, rawData);
|
let encoded = await crypt.encryptGCM(key, senderNonce, rawData);
|
||||||
|
|
||||||
crypt.increaseNonce(senderNonce);
|
crypt.increaseNonce(senderNonce);
|
||||||
@@ -219,7 +213,7 @@ class Dial {
|
|||||||
return dataToSend;
|
return dataToSend;
|
||||||
};
|
};
|
||||||
|
|
||||||
let cgmReader = new reader.Multiple(async r => {
|
let cgmReader = new reader.Multiple(async (r) => {
|
||||||
try {
|
try {
|
||||||
let dSizeBytes = await reader.readN(rd, 2),
|
let dSizeBytes = await reader.readN(rd, 2),
|
||||||
dSize = 0;
|
dSize = 0;
|
||||||
@@ -236,7 +230,10 @@ class Dial {
|
|||||||
|
|
||||||
crypt.increaseNonce(receiverNonce);
|
crypt.increaseNonce(receiverNonce);
|
||||||
|
|
||||||
r.feed(new reader.Buffer(new Uint8Array(decoded), () => {}), () => {});
|
r.feed(
|
||||||
|
new reader.Buffer(new Uint8Array(decoded), () => {}),
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
r.closeWithReason(e);
|
r.closeWithReason(e);
|
||||||
}
|
}
|
||||||
@@ -245,8 +242,12 @@ class Dial {
|
|||||||
return {
|
return {
|
||||||
reader: cgmReader,
|
reader: cgmReader,
|
||||||
sender: sd,
|
sender: sd,
|
||||||
ws: ws
|
ws: ws,
|
||||||
};
|
};
|
||||||
|
} catch (e) {
|
||||||
|
ws.close();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +329,7 @@ export class Socket {
|
|||||||
},
|
},
|
||||||
outbound(data) {
|
outbound(data) {
|
||||||
callbacks.traffic(0, data.length);
|
callbacks.traffic(0, data.length);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let streamHandler = new streams.Streams(conn.reader, conn.sender, {
|
let streamHandler = new streams.Streams(conn.reader, conn.sender, {
|
||||||
@@ -357,12 +358,12 @@ export class Socket {
|
|||||||
// risk sending things out
|
// risk sending things out
|
||||||
conn.ws.close();
|
conn.ws.close();
|
||||||
callbacks.close(e);
|
callbacks.close(e);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
callbacks.connected();
|
callbacks.connected();
|
||||||
|
|
||||||
streamHandler.serve().catch(e => {
|
streamHandler.serve().catch((e) => {
|
||||||
if (process.env.NODE_ENV !== "development") {
|
if (process.env.NODE_ENV !== "development") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,3 +75,35 @@ export function separateBuffer(buf, max) {
|
|||||||
start += remain;
|
start += remain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an Uint8Array out of given binary string
|
||||||
|
*
|
||||||
|
* @param {string} str binary string
|
||||||
|
*
|
||||||
|
* @returns {Uint8Array} Separated buffers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function buildBufferFromString(str) {
|
||||||
|
let r = [],
|
||||||
|
t = [];
|
||||||
|
|
||||||
|
for (let i in str) {
|
||||||
|
let c = str.charCodeAt(i);
|
||||||
|
|
||||||
|
while (c > 0xff) {
|
||||||
|
t.push(c & 0xff);
|
||||||
|
c >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r.push(c);
|
||||||
|
|
||||||
|
for (let j = t.length; j > 0; j--) {
|
||||||
|
r.push(t[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
t = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Uint8Array(r);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user