/// <summary> /// Initializes broker for startup. /// </summary> /// <param name="platform">Platform implementations</param> public Broker(AbstractPlatform platform) { Platform = platform; _sha256 = new SHA256(); KeyPair = new KeyPair(".broker.key"); KeyPair.Load(Platform.FileSystem); DsId = "broker-" + UrlBase64.Encode(_sha256.ComputeHash(KeyPair.EncodedPublicKey)); ClientHandler = new ClientHandler(); HttpHandler = new HttpHandler(this); BrokerTree = new BrokerTree(this); Handshake = new Handshake(this); }
/// <summary> /// Generates the shared secret for connecting to the broker. /// </summary> /// <returns>Shared secret</returns> /// <param name="tempKey">Temporary key from server</param> public byte[] GenerateSharedSecret(string tempKey) { var decoded = UrlBase64.Decode(tempKey); var privateKey = ((ECPrivateKeyParameters)BcKeyPair.Private); var param = privateKey.Parameters; var point = param.Curve.DecodePoint(decoded); var spec = new ECPublicKeyParameters(point, param); point = spec.Q.Multiply(privateKey.D); var bi = point.X.ToBigInteger(); return(Normalize(bi.ToByteArray())); }
/// <summary> /// Handles an incoming HTTP post request to /conn. /// </summary> /// <param name="postedData">JSON data that contains information about the connecting client.</param> /// <param name="dsId">DSLink identifier for connecting client.</param> /// <param name="token">Optional token for broker authentication.</param> /// <returns>Constructed client object from provided data.</returns> public Client HandleHandshake(string postedData, string dsId, string token = null) { var jsonIn = JObject.Parse(postedData); var client = new Client(); client.Name = dsIdToName(dsId); client.TempKey = new KeyPair(); if (string.IsNullOrEmpty(dsId)) { throw new Exception("dsId must not be null or empty."); } else { if (!ValidateDsId(dsId)) { throw new Exception("Invalid dsId was provided."); } client.DsId = dsId; } if (token != null) { client.Token = token; } if (jsonIn["isRequester"] == null && jsonIn["isResponder"] == null) { throw new Exception("Neither isRequester or isResponder was provided."); } if (jsonIn["publicKey"] == null || jsonIn["publicKey"].Type != JTokenType.String) { throw new Exception("publicKey was not provided or it is an invalid type."); } else { client.PublicKey = jsonIn["publicKey"].ToObject <string>(); } if (jsonIn["isRequester"] != null && jsonIn["isRequester"].Type == JTokenType.Boolean) { client.Requester = jsonIn["isRequester"].ToObject <bool>(); } else if (jsonIn["isRequester"] != null) { throw new Exception("isRequester was provided, but it is an invalid type."); } if (jsonIn["isResponder"] != null && jsonIn["isResponder"].Type == JTokenType.Boolean) { client.Responder = jsonIn["isResponder"].ToObject <bool>(); } else if (jsonIn["isResponder"] != null) { throw new Exception("isResponder was provided, but it is an invalid type."); } if (jsonIn["version"] == null || jsonIn["version"].Type != JTokenType.String) { throw new Exception("version was not provided or invalid type."); } else { client.ReportingVersion = jsonIn["version"].ToObject <string>(); } if (jsonIn["formats"] != null && jsonIn["formats"].Type != JTokenType.Array) { throw new Exception("formats was provided, but it is an invalid type."); } else if (jsonIn["formats"] == null) { // Server assumes client understands the JSON format if formats isn't provided. client.Formats = new List <string> { "json" }; } else { var jarray = jsonIn["formats"].ToObject <JArray>(); var list = new List <string>(); foreach (JToken jtoken in jarray) { if (jtoken.Type != JTokenType.String) { throw new Exception("formats was provided as an array, but contained a value other than a string."); } list.Add(jtoken.ToObject <string>()); } // If the DSLink SDK provides an empty formats list, let's assume they understand JSON. // If they don't... I'm not sure what to tell them. if (list.Count == 0) { client.Formats = new List <string> { "json" }; } client.Formats = list; } if (jsonIn["enableWebSocketCompression"] != null && jsonIn["enableWebSocketCompression"].Type == JTokenType.Boolean) { client.WebSocketCompression = jsonIn["enableWebSocketCompression"].ToObject <bool>(); } else if (jsonIn["enableWebSocketCompression"] != null) { throw new Exception("enableWebSocketCompression was provided, but it is an invalid type."); } client.Name = _broker.BrokerTree.InitDSLink(client.Name, client.DsId); client.HandshakeResponse["dsId"] = _broker.DsId; client.HandshakeResponse["publicKey"] = UrlBase64.Encode(_broker.KeyPair.EncodedPublicKey); client.HandshakeResponse["wsUri"] = "/ws"; client.HandshakeResponse["httpUri"] = "/http"; client.HandshakeResponse["tempKey"] = UrlBase64.Encode(client.TempKey.EncodedPublicKey); client.HandshakeResponse["salt"] = Encoding.UTF8.GetString(GenerateSalt(), 0, 32); if (client.Responder) { client.HandshakeResponse["path"] = "/downstream/" + client.Name; } client.HandshakeResponse["format"] = "json"; // TODO: use actual format return(client); }