2using System.Collections.Generic;
4using System.Security.Cryptography;
5using System.Security.Cryptography.X509Certificates;
7using System.Threading.Tasks;
190 private readonly Dictionary<string, KeyValuePair<byte[], X509Certificate2>> certificates =
new Dictionary<string, KeyValuePair<byte[], X509Certificate2>>();
191 private int seqNr = 0;
202 #region Neuro-Foundation V1 handlers
204 this.
RegisterIqGetHandler(
"getToken", NamespaceProvisioningTokenNeuroFoundationV1, this.GetTokenHandler,
true);
205 this.
RegisterIqGetHandler(
"getTokenChallengeResponse", NamespaceProvisioningTokenNeuroFoundationV1, this.GetTokenChallengeResponseHandler,
false);
206 this.
RegisterIqGetHandler(
"getCertificate", NamespaceProvisioningTokenNeuroFoundationV1, this.GetCertificateHandler,
false);
208 this.
RegisterIqGetHandler(
"isFriend", NamespaceProvisioningDeviceNeuroFoundationV1, this.IsFriendHandler,
true);
209 this.
RegisterIqGetHandler(
"canRead", NamespaceProvisioningDeviceNeuroFoundationV1, this.CanReadHandler,
false);
210 this.
RegisterIqGetHandler(
"canControl", NamespaceProvisioningDeviceNeuroFoundationV1, this.CanControlHandler,
false);
212 this.
RegisterIqSetHandler(
"isFriendRule", NamespaceProvisioningOwnerNeuroFoundationV1, this.IsFriendRuleHandler,
true);
213 this.
RegisterIqSetHandler(
"canReadRule", NamespaceProvisioningOwnerNeuroFoundationV1, this.CanReadRuleHandler,
false);
214 this.
RegisterIqSetHandler(
"canControlRule", NamespaceProvisioningOwnerNeuroFoundationV1, this.CanControlRuleHandler,
false);
215 this.
RegisterIqSetHandler(
"clearCache", NamespaceProvisioningOwnerNeuroFoundationV1, this.ClearCacheHandler,
false);
216 this.
RegisterIqGetHandler(
"getDevices", NamespaceProvisioningOwnerNeuroFoundationV1, this.GetDevicesHandler,
false);
217 this.
RegisterIqSetHandler(
"deleteRules", NamespaceProvisioningOwnerNeuroFoundationV1, this.DeleteRulesHandler,
false);
219 this.
RegisterIqSetHandler(
"register", NamespaceIoTDiscoveryNeuroFoundationV1, this.RegisterHandler,
true);
220 this.
RegisterIqSetHandler(
"mine", NamespaceIoTDiscoveryNeuroFoundationV1, this.MineHandler,
false);
221 this.
RegisterIqSetHandler(
"update", NamespaceIoTDiscoveryNeuroFoundationV1, this.UpdateHandler,
false);
222 this.
RegisterIqSetHandler(
"remove", NamespaceIoTDiscoveryNeuroFoundationV1, this.RemoveHandler,
false);
223 this.
RegisterIqSetHandler(
"unregister", NamespaceIoTDiscoveryNeuroFoundationV1, this.UnregisterHandler,
false);
224 this.
RegisterIqSetHandler(
"disown", NamespaceIoTDiscoveryNeuroFoundationV1, this.DisownHandler,
false);
225 this.
RegisterIqGetHandler(
"search", NamespaceIoTDiscoveryNeuroFoundationV1, this.SearchHandler,
false);
227 this.
RegisterIqGetHandler(
"getPackageInfo", NamespaceSoftwareUpdatesNeuroFoundationV1, this.GetPackageInfoHandler,
true);
228 this.
RegisterIqGetHandler(
"getPackages", NamespaceSoftwareUpdatesNeuroFoundationV1, this.GetPackagesHandler,
false);
229 this.
RegisterIqSetHandler(
"subscribe", NamespaceSoftwareUpdatesNeuroFoundationV1, this.SubscribeHandler,
false);
230 this.
RegisterIqSetHandler(
"unsubscribe", NamespaceSoftwareUpdatesNeuroFoundationV1, this.UnsubscribeHandler,
false);
231 this.
RegisterIqGetHandler(
"getSubscriptions", NamespaceSoftwareUpdatesNeuroFoundationV1, this.GetSubscriptionsHandler,
false);
235 #region IEEE V1 handlers
237 this.
RegisterIqGetHandler(
"getToken", NamespaceProvisioningTokenIeeeV1, this.GetTokenHandler,
true);
238 this.
RegisterIqGetHandler(
"getTokenChallengeResponse", NamespaceProvisioningTokenIeeeV1, this.GetTokenChallengeResponseHandler,
false);
239 this.
RegisterIqGetHandler(
"getCertificate", NamespaceProvisioningTokenIeeeV1, this.GetCertificateHandler,
false);
241 this.
RegisterIqGetHandler(
"isFriend", NamespaceProvisioningDeviceIeeeV1, this.IsFriendHandler,
true);
242 this.
RegisterIqGetHandler(
"canRead", NamespaceProvisioningDeviceIeeeV1, this.CanReadHandler,
false);
243 this.
RegisterIqGetHandler(
"canControl", NamespaceProvisioningDeviceIeeeV1, this.CanControlHandler,
false);
245 this.
RegisterIqSetHandler(
"isFriendRule", NamespaceProvisioningOwnerIeeeV1, this.IsFriendRuleHandler,
true);
246 this.
RegisterIqSetHandler(
"canReadRule", NamespaceProvisioningOwnerIeeeV1, this.CanReadRuleHandler,
false);
247 this.
RegisterIqSetHandler(
"canControlRule", NamespaceProvisioningOwnerIeeeV1, this.CanControlRuleHandler,
false);
248 this.
RegisterIqSetHandler(
"clearCache", NamespaceProvisioningOwnerIeeeV1, this.ClearCacheHandler,
false);
249 this.
RegisterIqGetHandler(
"getDevices", NamespaceProvisioningOwnerIeeeV1, this.GetDevicesHandler,
false);
250 this.
RegisterIqSetHandler(
"deleteRules", NamespaceProvisioningOwnerIeeeV1, this.DeleteRulesHandler,
false);
256 this.
RegisterIqSetHandler(
"unregister", NamespaceIoTDiscoveryIeeeV1, this.UnregisterHandler,
false);
260 this.
RegisterIqGetHandler(
"getPackageInfo", NamespaceSoftwareUpdatesIeeeV1, this.GetPackageInfoHandler,
true);
261 this.
RegisterIqGetHandler(
"getPackages", NamespaceSoftwareUpdatesIeeeV1, this.GetPackagesHandler,
false);
262 this.
RegisterIqSetHandler(
"subscribe", NamespaceSoftwareUpdatesIeeeV1, this.SubscribeHandler,
false);
263 this.
RegisterIqSetHandler(
"unsubscribe", NamespaceSoftwareUpdatesIeeeV1, this.UnsubscribeHandler,
false);
264 this.
RegisterIqGetHandler(
"getSubscriptions", NamespaceSoftwareUpdatesIeeeV1, this.GetSubscriptionsHandler,
false);
274 this.
RegisterIqSetHandler(
"unregister", NamespaceIoTDiscoveryXsfV0, this.UnregisterHandler,
false);
286 #region Neuro-Foundation V1 handlers
288 this.
UnregisterIqGetHandler(
"getToken", NamespaceProvisioningTokenNeuroFoundationV1, this.GetTokenHandler,
true);
289 this.
UnregisterIqGetHandler(
"getTokenChallengeResponse", NamespaceProvisioningTokenNeuroFoundationV1, this.GetTokenChallengeResponseHandler,
false);
290 this.
UnregisterIqGetHandler(
"getCertificate", NamespaceProvisioningTokenNeuroFoundationV1, this.GetCertificateHandler,
false);
292 this.
UnregisterIqGetHandler(
"isFriend", NamespaceProvisioningDeviceNeuroFoundationV1, this.IsFriendHandler,
true);
293 this.
UnregisterIqGetHandler(
"canRead", NamespaceProvisioningDeviceNeuroFoundationV1, this.CanReadHandler,
false);
294 this.
UnregisterIqGetHandler(
"canControl", NamespaceProvisioningDeviceNeuroFoundationV1, this.CanControlHandler,
false);
296 this.
UnregisterIqSetHandler(
"isFriendRule", NamespaceProvisioningOwnerNeuroFoundationV1, this.IsFriendRuleHandler,
true);
297 this.
UnregisterIqSetHandler(
"canReadRule", NamespaceProvisioningOwnerNeuroFoundationV1, this.CanReadRuleHandler,
false);
298 this.
UnregisterIqSetHandler(
"canControlRule", NamespaceProvisioningOwnerNeuroFoundationV1, this.CanControlRuleHandler,
false);
299 this.
UnregisterIqSetHandler(
"clearCache", NamespaceProvisioningOwnerNeuroFoundationV1, this.ClearCacheHandler,
false);
300 this.
UnregisterIqGetHandler(
"getDevices", NamespaceProvisioningOwnerNeuroFoundationV1, this.GetDevicesHandler,
false);
301 this.
UnregisterIqSetHandler(
"deleteRules", NamespaceProvisioningOwnerNeuroFoundationV1, this.DeleteRulesHandler,
false);
303 this.
UnregisterIqSetHandler(
"register", NamespaceIoTDiscoveryNeuroFoundationV1, this.UnregisterHandler,
true);
307 this.
UnregisterIqSetHandler(
"unregister", NamespaceIoTDiscoveryNeuroFoundationV1, this.UnregisterHandler,
false);
311 this.
UnregisterIqGetHandler(
"getPackageInfo", NamespaceSoftwareUpdatesNeuroFoundationV1, this.GetPackageInfoHandler,
true);
312 this.
UnregisterIqGetHandler(
"getPackages", NamespaceSoftwareUpdatesNeuroFoundationV1, this.GetPackagesHandler,
false);
313 this.
UnregisterIqSetHandler(
"subscribe", NamespaceSoftwareUpdatesNeuroFoundationV1, this.SubscribeHandler,
false);
314 this.
UnregisterIqSetHandler(
"unsubscribe", NamespaceSoftwareUpdatesNeuroFoundationV1, this.UnsubscribeHandler,
false);
315 this.
UnregisterIqGetHandler(
"getSubscriptions", NamespaceSoftwareUpdatesNeuroFoundationV1, this.GetSubscriptionsHandler,
false);
319 #region IEEE V1 handlers
322 this.
UnregisterIqGetHandler(
"getTokenChallengeResponse", NamespaceProvisioningTokenIeeeV1, this.GetTokenChallengeResponseHandler,
false);
323 this.
UnregisterIqGetHandler(
"getCertificate", NamespaceProvisioningTokenIeeeV1, this.GetCertificateHandler,
false);
327 this.
UnregisterIqGetHandler(
"canControl", NamespaceProvisioningDeviceIeeeV1, this.CanControlHandler,
false);
329 this.
UnregisterIqSetHandler(
"isFriendRule", NamespaceProvisioningOwnerIeeeV1, this.IsFriendRuleHandler,
true);
330 this.
UnregisterIqSetHandler(
"canReadRule", NamespaceProvisioningOwnerIeeeV1, this.CanReadRuleHandler,
false);
331 this.
UnregisterIqSetHandler(
"canControlRule", NamespaceProvisioningOwnerIeeeV1, this.CanControlRuleHandler,
false);
332 this.
UnregisterIqSetHandler(
"clearCache", NamespaceProvisioningOwnerIeeeV1, this.ClearCacheHandler,
false);
333 this.
UnregisterIqGetHandler(
"getDevices", NamespaceProvisioningOwnerIeeeV1, this.GetDevicesHandler,
false);
334 this.
UnregisterIqSetHandler(
"deleteRules", NamespaceProvisioningOwnerIeeeV1, this.DeleteRulesHandler,
false);
344 this.
UnregisterIqGetHandler(
"getPackageInfo", NamespaceSoftwareUpdatesIeeeV1, this.GetPackageInfoHandler,
true);
345 this.
UnregisterIqGetHandler(
"getPackages", NamespaceSoftwareUpdatesIeeeV1, this.GetPackagesHandler,
false);
347 this.
UnregisterIqSetHandler(
"unsubscribe", NamespaceSoftwareUpdatesIeeeV1, this.UnsubscribeHandler,
false);
348 this.
UnregisterIqGetHandler(
"getSubscriptions", NamespaceSoftwareUpdatesIeeeV1, this.GetSubscriptionsHandler,
false);
365 this.tokenRequests =
null;
367 this.registryAccounts?.
Clear();
368 this.registryAccounts?.
Dispose();
369 this.registryAccounts =
null;
378 #region Provisioning, Tokens
380 private Task GetTokenHandler(
object Sender,
IqEventArgs e)
384 string Base64 = e.
Query.InnerText;
385 byte[] Bin = Convert.FromBase64String(Base64);
386 X509Certificate2 Certificate =
new X509Certificate2(Bin);
388 if (Certificate.Verify())
391 string Response = Convert.ToBase64String(Bin);
392 Bin = ((RSACryptoServiceProvider)Certificate.PublicKey.Key).Encrypt(Bin,
true);
393 string Challenge = Convert.ToBase64String(Bin);
401 SeqNr = this.seqNr++;
405 this.tokenRequests.
Add(SeqNr,
new KeyValuePair<
string, KeyValuePair<
byte[], X509Certificate2>>(Response,
406 new KeyValuePair<
byte[], X509Certificate2>(Bin, Certificate)));
409 e.
IqResult(
"<getTokenChallenge xmlns='" + e.
Query.NamespaceURI +
"' seqnr='" +
410 SeqNr.ToString() +
"'>" + Challenge +
"</getTokenChallenge>", e.
To);
420 return Task.CompletedTask;
423 private Task GetTokenChallengeResponseHandler(
object Sender,
IqEventArgs e)
425 XmlElement E = e.
Query;
428 if (!this.tokenRequests.
TryGetValue(SeqNr, out KeyValuePair<
string, KeyValuePair<
byte[], X509Certificate2>> Rec))
432 this.tokenRequests.
Remove(SeqNr);
434 string Response = E.InnerText;
435 if (Response != Rec.Key)
440 string Token = Convert.ToBase64String(Bin);
442 lock (this.certificates)
444 this.certificates[Token] = Rec.Value;
447 e.
IqResult(
"<getTokenResponse xmlns='" + e.
Query.NamespaceURI +
"' token='" + e.
To +
":" + Token +
"'/>",
452 return Task.CompletedTask;
455 private class TokenChallengesRecord
458 public Dictionary<string, bool> TokensToChallenge;
460 public List<ThingReference> Nodes =
null;
461 public List<string> Fields =
null;
463 public string[] ServiceTokens;
464 public string[] DeviceTokens;
465 public string[] UserTokens;
466 public bool Allowed =
false;
468 public int NrTokensToChallenge;
469 public bool AllOk =
true;
473 private class TokenChallengeRecord
475 public TokenChallengesRecord Challenges;
477 public string Response;
482 TokenChallengeRecord Rec2 = (TokenChallengeRecord)e.
State;
483 TokenChallengesRecord Rec = Rec2.Challenges;
487 if (e.
Ok && !(E is
null) && E.LocalName ==
"tokenChallengeResponse" && E.InnerText == Rec2.Response)
489 this.challengedTokens.
Add(e.
From +
" " + Rec2.Token,
true);
491 lock (Rec.TokensToChallenge)
493 Rec.TokensToChallenge[Rec2.Token] =
true;
494 Rec.NrTokensToChallenge--;
495 Done = Rec.NrTokensToChallenge == 0;
500 lock (Rec.TokensToChallenge)
503 Rec.NrTokensToChallenge--;
504 Done = Rec.NrTokensToChallenge == 0;
515 await this.TestAndSendCanReadResponse(Rec.Jid, Rec.e, Rec.Allowed, Rec.FieldTypes, Rec.Nodes, Rec.Fields,
516 Rec.ServiceTokens, Rec.DeviceTokens, Rec.UserTokens, Rec.QueryVersion);
523 await this.TestAndSendCanControlResponse(Rec.Jid, Rec.e, Rec.Allowed, Rec.Nodes, Rec.Fields,
524 Rec.ServiceTokens, Rec.DeviceTokens, Rec.UserTokens, Rec.QueryVersion);
529 private void AddValidTokens(Dictionary<string, bool> TokensToChallenge,
string[] Tokens,
string From)
531 foreach (
string Token
in Tokens)
533 if (!TokensToChallenge.ContainsKey(Token) && !
this.challengedTokens.ContainsKey(From +
" " + Token))
535 lock (this.certificates)
537 if (!this.certificates.ContainsKey(Token))
541 TokensToChallenge[Token] =
false;
546 private Task GetCertificateHandler(
object Sender,
IqEventArgs e)
548 KeyValuePair<byte[], X509Certificate2> Rec;
553 i = Token.IndexOf(
':');
556 string Address = Token.Substring(0, i);
557 Token = Token.Substring(i + 1);
562 return Task.CompletedTask;
566 lock (this.certificates)
568 Found = this.certificates.TryGetValue(Token, out Rec);
574 e.
IqResult(
"<certificate xmlns='" + e.
Query.NamespaceURI +
"'>" + Convert.ToBase64String(Rec.Key) +
"</certificate>", e.
To);
576 return Task.CompletedTask;
581 #region Provisioning, Device interface
583 private async Task IsFriendHandler(
object Sender,
IqEventArgs e)
590 Registration Registration = await this.GetRegistration(JID,
string.Empty,
string.Empty,
string.Empty, QueryVersion,
null);
599 AreFrieds =
Rule.CanSubscribeToPresence;
608 AreFrieds =
Rule.CanSubscribeToPresence;
615 AreFrieds =
Rule.CanSubscribeToPresence;
623 RemoteJID = RemoteJID,
624 CanSubscribeToPresence =
false
629 StringBuilder Xml =
new StringBuilder();
631 Xml.Append(
"<isFriend xmlns='");
633 Xml.Append(
"' jid='");
635 Xml.Append(
"' remoteJid='");
637 Xml.Append(
"' key='");
647 await e.
IqResult(
"<isFriendResponse xmlns='" + e.
Query.NamespaceURI +
"' jid='" +
XML.
Encode(RemoteJID) +
"' result='" +
651 private async Task CanReadHandler(
object Sender,
IqEventArgs e)
653 List<ThingReference> Nodes =
null;
654 List<string> Fields =
null;
655 XmlElement E = e.
Query;
657 string ServiceToken =
string.Empty;
658 string DeviceToken =
string.Empty;
659 string UserToken =
string.Empty;
664 foreach (XmlAttribute Attr
in E.Attributes)
669 ServiceToken = Attr.Value;
673 DeviceToken = Attr.Value;
677 UserToken = Attr.Value;
721 foreach (XmlNode N
in E.ChildNodes)
727 Nodes =
new List<ThingReference>();
730 Nodes.Add(this.ParseNodeInfo(E));
735 Fields =
new List<string>();
742 string[] ServiceTokens = ServiceToken.Split(space, StringSplitOptions.RemoveEmptyEntries);
743 string[] DeviceTokens = DeviceToken.Split(space, StringSplitOptions.RemoveEmptyEntries);
744 string[] UserTokens = UserToken.Split(space, StringSplitOptions.RemoveEmptyEntries);
745 Dictionary<string, bool> TokensToChallenge =
null;
746 int NrTokensToChallenge;
748 if (ServiceTokens.Length == 0 && DeviceTokens.Length == 0 && UserTokens.Length == 0)
749 NrTokensToChallenge = 0;
752 TokensToChallenge =
new Dictionary<string, bool>();
754 this.AddValidTokens(TokensToChallenge, ServiceTokens, e.
From.
Address);
755 this.AddValidTokens(TokensToChallenge, DeviceTokens, e.
From.
Address);
756 this.AddValidTokens(TokensToChallenge, UserTokens, e.
From.
Address);
758 NrTokensToChallenge = TokensToChallenge.Count;
759 if (NrTokensToChallenge > 0)
761 TokenChallengesRecord Rec =
new TokenChallengesRecord()
763 TokensToChallenge = TokensToChallenge,
766 FieldTypes = FieldTypes,
768 ServiceTokens = ServiceTokens,
769 DeviceTokens = DeviceTokens,
770 UserTokens = UserTokens,
772 NrTokensToChallenge = NrTokensToChallenge,
775 QueryVersion = QueryVersion
778 string[] Tokens =
new string[TokensToChallenge.Count];
779 TokensToChallenge.Keys.CopyTo(Tokens, 0);
781 foreach (
string Token
in Tokens)
783 KeyValuePair<byte[], X509Certificate2> Certificate;
785 lock (this.certificates)
787 Certificate = this.certificates[Token];
791 string Response = Convert.ToBase64String(Bin);
792 Bin = ((RSACryptoServiceProvider)Certificate.Value.PublicKey.Key).Encrypt(Bin,
true);
793 string Challenge = Convert.ToBase64String(Bin);
795 TokenChallengeRecord Rec2 =
new TokenChallengeRecord()
802 await this.Server.SendIqRequest(
"get", e.
To, e.
From,
string.
Empty,
803 "<tokenChallenge xmlns='" + NamespaceProvisioningToken(QueryVersion) +
"' token='" +
804 XML.
Encode(Token) +
"'>" + Challenge +
"</tokenChallenge>",
this.TokenChallengeResponse, Rec2);
811 await this.TestAndSendCanReadResponse(Jid, e,
true, FieldTypes, Nodes, Fields, ServiceTokens, DeviceTokens, UserTokens, QueryVersion);
815 List<ThingReference> Nodes, List<string> Fields,
string[] ServiceTokens,
string[] DeviceTokens,
string[] UserTokens,
823 List<ThingReference> NodesAllowed =
null;
826 if (Nodes is
null || Nodes.Count == 0)
827 Nodes =
new List<ThingReference>() { ThingReference.Empty };
831 RemoteJid = RemoteJID,
832 RemoteDomain = RemoteDomain,
834 ServiceTokens = ServiceTokens,
835 DeviceTokens = DeviceTokens,
836 UserTokens = UserTokens
839 if (!(Fields is
null))
841 Context.Names =
new Dictionary<string, bool>();
843 foreach (
string Field in Fields)
866 Partition = Node.Partition
874 if (!(
Rule.Rules is
null))
888 if (NodesAllowed is
null)
889 NodesAllowed =
new List<ThingReference>();
891 NodesAllowed.Add(Node);
897 StringBuilder Xml =
new StringBuilder();
899 Xml.Append(
"<canRead xmlns='");
900 Xml.Append(NamespaceProvisioningOwner(
Registration.OwnerVersion));
901 Xml.Append(
"' jid='");
903 Xml.Append(
"' remoteJid='");
905 Xml.Append(
"' key='");
909 Xml.Append(
"' all='true");
912 if ((FieldTypes &
FieldType.Historical) != 0)
913 Xml.Append(
"' h='true");
915 if ((FieldTypes &
FieldType.Momentary) != 0)
916 Xml.Append(
"' m='true");
919 Xml.Append(
"' p='true");
921 if ((FieldTypes &
FieldType.Status) != 0)
922 Xml.Append(
"' s='true");
924 if ((FieldTypes &
FieldType.Computed) != 0)
925 Xml.Append(
"' c='true");
927 if ((FieldTypes &
FieldType.Identity) != 0)
928 Xml.Append(
"' i='true");
931 this.AppendTokens(Xml,
"st", ServiceTokens);
932 this.AppendTokens(Xml,
"dt", DeviceTokens);
933 this.AppendTokens(Xml,
"ut", UserTokens);
938 this.AppendNode(Xml, Node);
942 foreach (
string FieldName
in Context.Names.Keys)
944 Xml.Append(
"<f n='");
950 Xml.Append(
"</canRead>");
955 await this.SendCanReadResponse(Jid, e, !(NodesAllowed is
null),
Context.Types, NodesAllowed,
Context?.Names?.Keys, QueryVersion);
958 await this.SendCanReadResponse(Jid, e,
false, 0,
null,
null, QueryVersion);
961 private void AppendTokens(StringBuilder Xml,
string Attribute,
string[] Tokens)
963 if (!(Tokens is
null) && Tokens.Length > 0)
968 Xml.Append(Attribute);
971 foreach (
string Token
in Tokens)
984 List<ThingReference> Nodes, IEnumerable<string> Fields,
NamespaceSet Version)
986 StringBuilder Xml =
new StringBuilder();
988 Xml.Append(
"<canReadResponse xmlns='");
989 Xml.Append(NamespaceProvisioningOwner(Version));
990 Xml.Append(
"' result='");
992 Xml.Append(
"' jid='");
998 Xml.Append(
"' all='true");
1001 if (FieldTypes.HasFlag(
FieldType.Momentary))
1002 Xml.Append(
"' m='true");
1005 Xml.Append(
"' p='true");
1007 if (FieldTypes.HasFlag(
FieldType.Status))
1008 Xml.Append(
"' s='true");
1010 if (FieldTypes.HasFlag(
FieldType.Computed))
1011 Xml.Append(
"' c='true");
1013 if (FieldTypes.HasFlag(
FieldType.Identity))
1014 Xml.Append(
"' i='true");
1016 if (FieldTypes.HasFlag(
FieldType.Historical))
1017 Xml.Append(
"' h='true");
1020 if (Nodes is
null && Fields is
null)
1026 if (!(Nodes is
null) && (Nodes.Count != 1 || !Nodes[0].IsEmpty))
1029 this.AppendNode(Xml, Node);
1032 if (!(Fields is
null))
1034 foreach (
string FieldName
in Fields)
1036 Xml.Append(
"<f n='");
1042 Xml.Append(
"</canReadResponse>");
1053 Xml.Append(
"<nd id='");
1056 if (!
string.IsNullOrEmpty(Node.
SourceId))
1058 Xml.Append(
"' src='");
1062 if (!
string.IsNullOrEmpty(Node.
Partition))
1064 Xml.Append(
"' pt='");
1071 private static readonly
char[] space =
new char[] {
' ' };
1081 lock (this.certificates)
1083 if (this.certificates.TryGetValue(Token, out KeyValuePair<
byte[], X509Certificate2> Rec))
1085 Certificate = Rec.Value;
1096 private async Task CanControlHandler(
object Sender,
IqEventArgs e)
1098 List<ThingReference> Nodes =
null;
1099 List<string> ParameterNames =
null;
1100 XmlElement E = e.
Query;
1101 string ServiceToken =
string.Empty;
1102 string DeviceToken =
string.Empty;
1103 string UserToken =
string.Empty;
1107 foreach (XmlAttribute Attr
in E.Attributes)
1112 ServiceToken = Attr.Value;
1116 DeviceToken = Attr.Value;
1120 UserToken = Attr.Value;
1129 foreach (XmlNode N
in E.ChildNodes)
1131 switch (N.LocalName)
1135 Nodes =
new List<ThingReference>();
1138 Nodes.Add(this.ParseNodeInfo(E));
1142 if (ParameterNames is
null)
1143 ParameterNames =
new List<string>();
1150 string[] ServiceTokens = ServiceToken.Split(space, StringSplitOptions.RemoveEmptyEntries);
1151 string[] DeviceTokens = DeviceToken.Split(space, StringSplitOptions.RemoveEmptyEntries);
1152 string[] UserTokens = UserToken.Split(space, StringSplitOptions.RemoveEmptyEntries);
1153 Dictionary<string, bool> TokensToChallenge =
null;
1154 int NrTokensToChallenge;
1156 if (ServiceTokens.Length == 0 && DeviceTokens.Length == 0 && UserTokens.Length == 0)
1157 NrTokensToChallenge = 0;
1160 TokensToChallenge =
new Dictionary<string, bool>();
1162 this.AddValidTokens(TokensToChallenge, ServiceTokens, e.
From.
Address);
1163 this.AddValidTokens(TokensToChallenge, DeviceTokens, e.
From.
Address);
1164 this.AddValidTokens(TokensToChallenge, UserTokens, e.
From.
Address);
1166 NrTokensToChallenge = TokensToChallenge.Count;
1167 if (NrTokensToChallenge > 0)
1169 TokenChallengesRecord Rec =
new TokenChallengesRecord()
1171 TokensToChallenge = TokensToChallenge,
1173 Fields = ParameterNames,
1175 ServiceTokens = ServiceTokens,
1176 DeviceTokens = DeviceTokens,
1177 UserTokens = UserTokens,
1179 NrTokensToChallenge = NrTokensToChallenge,
1182 QueryVersion = QueryVersion
1185 string[] Tokens =
new string[TokensToChallenge.Count];
1186 TokensToChallenge.Keys.CopyTo(Tokens, 0);
1188 foreach (
string Token
in Tokens)
1190 KeyValuePair<byte[], X509Certificate2> Certificate;
1192 lock (this.certificates)
1194 Certificate = this.certificates[Token];
1198 string Response = System.Convert.ToBase64String(Bin);
1199 Bin = ((RSACryptoServiceProvider)Certificate.Value.PublicKey.Key).Encrypt(Bin,
true);
1200 string Challenge = System.Convert.ToBase64String(Bin);
1202 TokenChallengeRecord Rec2 =
new TokenChallengeRecord()
1209 await this.Server.SendIqRequest(
"get", e.
To, e.
From,
string.
Empty,
1210 "<tokenChallenge xmlns='" + NamespaceProvisioningToken(QueryVersion) +
"' token='" +
1211 XML.
Encode(Token) +
"'>" + Challenge +
"</tokenChallenge>",
this.TokenChallengeResponse, Rec2);
1218 await this.TestAndSendCanControlResponse(Jid, e,
true, Nodes, ParameterNames, ServiceTokens, DeviceTokens, UserTokens, QueryVersion);
1238 List<string> ParameterNames,
string[] ServiceTokens,
string[] DeviceTokens,
string[] UserTokens,
NamespaceSet QueryVersion)
1245 List<ThingReference> NodesAllowed =
null;
1248 if (Nodes is
null || Nodes.Count == 0)
1249 Nodes =
new List<ThingReference>() { ThingReference.Empty };
1253 RemoteJid = RemoteJID,
1254 RemoteDomain = RemoteDomain,
1255 ServiceTokens = ServiceTokens,
1256 DeviceTokens = DeviceTokens,
1257 UserTokens = UserTokens
1260 if (!(ParameterNames is
null))
1262 Context.Names =
new Dictionary<string, bool>();
1264 foreach (
string ParameterName
in ParameterNames)
1265 Context.Names[ParameterName] =
true;
1287 Partition = Node.Partition
1293 bool? Result =
null;
1295 if (!(
Rule.Rules is
null))
1300 if (Result.HasValue)
1305 if (Result.HasValue)
1309 if (NodesAllowed is
null)
1310 NodesAllowed =
new List<ThingReference>();
1312 NodesAllowed.Add(Node);
1318 StringBuilder Xml =
new StringBuilder();
1320 Xml.Append(
"<canControl xmlns='");
1321 Xml.Append(NamespaceProvisioningOwner(QueryVersion));
1322 Xml.Append(
"' jid='");
1324 Xml.Append(
"' remoteJid='");
1326 Xml.Append(
"' key='");
1329 this.AppendTokens(Xml,
"st", ServiceTokens);
1330 this.AppendTokens(Xml,
"dt", DeviceTokens);
1331 this.AppendTokens(Xml,
"ut", UserTokens);
1336 this.AppendNode(Xml, Node);
1340 foreach (
string FieldName
in Context.Names.Keys)
1342 Xml.Append(
"<p n='");
1348 Xml.Append(
"</canControl>");
1353 await this.SendCanControlResponse(Jid, e, !(NodesAllowed is
null), NodesAllowed,
Context?.Names?.Keys);
1356 await this.SendCanControlResponse(Jid, e,
false,
null,
null);
1360 IEnumerable<string> ParameterNames)
1362 StringBuilder Xml =
new StringBuilder();
1364 Xml.Append(
"<canControlResponse xmlns='");
1365 Xml.Append(e.
Query.NamespaceURI);
1366 Xml.Append(
"' result='");
1368 Xml.Append(
"' jid='");
1373 if (Nodes is
null && ParameterNames is
null)
1379 if (!(Nodes is
null))
1382 this.AppendNode(Xml, Node);
1385 if (!(ParameterNames is
null))
1387 foreach (
string FieldName
in ParameterNames)
1389 Xml.Append(
"<p n='");
1395 Xml.Append(
"</canControlResponse>");
1406 #region Provisioning, Owner interface
1408 private async Task IsFriendRuleHandler(
object Sender,
IqEventArgs e)
1419 if (!Guid.TryParse(Key, out Guid ObjectId))
1432 if (
Rule.JID != JID ||
Rule.RemoteJID != RemoteJID)
1438 Registration Registration = await this.GetRegistration(JID,
string.Empty,
string.Empty,
string.Empty,
null, QueryVersion);
1446 Log.
Informational(
"Presence subscription rule changed.", JID, OwnerJid,
"SubscriptionRule",
1447 new KeyValuePair<string, object>(
"RemoteJID", RemoteJID),
1448 new KeyValuePair<string, object>(
"Allowed", AreFrieds));
1453 if (
Rule.CanSubscribeToPresence != AreFrieds)
1455 Rule.CanSubscribeToPresence = AreFrieds;
1468 if (!(
Rule is
null))
1470 if (
Rule.CanSubscribeToPresence != AreFrieds)
1472 Rule.CanSubscribeToPresence = AreFrieds;
1481 RemoteJID = RemoteDomain,
1482 CanSubscribeToPresence = AreFrieds
1495 if (!(
Rule is
null))
1497 if (
Rule.CanSubscribeToPresence != AreFrieds)
1499 Rule.CanSubscribeToPresence = AreFrieds;
1508 RemoteJID =
string.
Empty,
1509 CanSubscribeToPresence = AreFrieds
1531 await this.RecommendBefriend(RemoteJID, JID, QueryVersion);
1533 catch (Exception ex)
1537 }, DateTime.Now.AddSeconds(5),
null);
1551 await this.Server.GetLastPresence(BareJid1, async (Sender, e) =>
1557 await this.Server.SendMessage(string.Empty, string.Empty, this.GetComponentAddress(e.To), e.From, string.Empty,
1558 "<unfriend xmlns='" + NamespaceProvisioningDevice(Version) +
"' jid='" + BareJid2 +
"'/>");
1561 catch (Exception ex)
1571 return this.MainDomain;
1583 await this.Server.GetLastPresence(BareJid, async (Sender, e) =>
1587 string Xml =
"<clearCache xmlns='" + NamespaceProvisioningDevice(Version) +
"'/>";
1592 await this.Server.SendIqRequest(
"set", From, e.
From,
string.
Empty, Xml, (sender2, e2) =>
1595 return this.Server.SendMessage(string.Empty, string.Empty, From, new XmppAddress(BareJid), string.Empty, Xml);
1597 return Task.CompletedTask;
1601 await this.Server.SendMessage(
string.Empty,
string.Empty, From,
new XmppAddress(BareJid),
string.Empty, Xml);
1603 catch (Exception ex)
1620 await this.Server.GetLastPresence(BareJid1, async (Sender, e) =>
1626 await this.Server.SendMessage(string.Empty, string.Empty, this.GetComponentAddress(e.To), e.From, string.Empty,
1627 "<friend xmlns='" + NamespaceProvisioningDevice(Version) +
"' jid='" + BareJid2 +
"'/>");
1630 catch (Exception ex)
1637 private async Task CanReadRuleHandler(
object Sender,
IqEventArgs e)
1646 if (!Guid.TryParse(Key, out Guid ObjectId))
1659 Rule Condition =
null;
1663 foreach (XmlNode N
in e.
Query.ChildNodes)
1665 if (N is XmlElement E)
1667 switch (E.LocalName)
1670 Node = this.ParseNodeInfo(E);
1674 List<string> Fields =
null;
1677 foreach (XmlAttribute Attr
in E.Attributes)
1718 foreach (XmlNode N2
in E.ChildNodes)
1720 if (N2 is XmlElement E2)
1722 switch (E2.LocalName)
1726 Fields =
new List<string>();
1736 Names = Fields?.ToArray(),
1737 Mask = (int)FieldTypes
1751 Value = GetDomain(RemoteJID)
1777 Condition =
new All();
1783 if (Condition is
null)
1817 new KeyValuePair<string, object>(
"RemoteJID", RemoteJID),
1818 new KeyValuePair<string, object>(
"Allowed", CanRead));
1827 private async Task CanControlRuleHandler(
object Sender,
IqEventArgs e)
1836 if (!Guid.TryParse(Key, out Guid ObjectId))
1849 Rule Condition =
null;
1853 foreach (XmlNode N
in e.
Query.ChildNodes)
1855 if (N is XmlElement E)
1857 switch (E.LocalName)
1860 Node = this.ParseNodeInfo(E);
1864 List<string> Parameters =
null;
1866 foreach (XmlNode N2
in E.ChildNodes)
1868 if (N2 is XmlElement E2)
1870 switch (E2.LocalName)
1873 if (Parameters is
null)
1874 Parameters =
new List<string>();
1884 Names = Parameters?.ToArray()
1898 Value = GetDomain(RemoteJID)
1924 Condition =
new All();
1930 if (Condition is
null)
1967 new KeyValuePair<string, object>(
"RemoteJID", RemoteJID),
1968 new KeyValuePair<string, object>(
"Allowed", CanControl));
1977 private async Task ClearCacheHandler(
object Sender,
IqEventArgs e)
1989 await this.ClearCache(R.
JID, R.Version);
2007 await this.ClearCache(Jid, R.Version);
2012 catch (Exception ex)
2018 private async Task GetDevicesHandler(
object Sender,
IqEventArgs e)
2022 XmlElement E = e.
Query;
2033 else if (MaxCount <= 0)
2039 List<KeyValuePair<Registration, IEnumerable<MetaDataTag>>> Found =
new List<KeyValuePair<Registration, IEnumerable<MetaDataTag>>>();
2042 IEnumerable<Registration> Registrations;
2045 "JID",
"NodeId",
"SourceId",
"Partition");
2049 if (Found.Count >= MaxCount)
2055 Found.Add(
new KeyValuePair<
Registration, IEnumerable<MetaDataTag>>(R, await LoadTags(R.
ObjectId)));
2060 catch (Exception ex)
2068 #region Thing Registry XEP-0347
2077 Result.Removed += UpdateRegistryAccount;
2088 catch (Exception ex)
2101 if (Account is
null)
2103 DateTime Now = DateTime.Now;
2114 Account.LastAction = DateTime.Now;
2118 Account2.LastAction = DateTime.Now;
2128 private async Task RegisterHandler(
object _,
IqEventArgs e)
2132 XmlElement E = e.
Query;
2137 Node = this.ParseNodeInfo(E);
2138 if (!this.ParseTags(e, E, out Dictionary<string, MetaDataTag> Tags, out
string Key))
2160 NrRegistrations = 1,
2162 FirstRegistration = DateTime.Now,
2163 Version = QueryVersion
2170 Registration.IsPublic =
true;
2175 Registration.IsPublic =
false;
2176 Registration.Owner =
string.
Empty;
2180 await SaveNewRegistrationTags(
Registration, this.GetArray(Tags));
2186 Registration.Key = Key;
2188 Registration.LastUpdate = DateTime.Now;
2192 Registration.IsPublic =
true;
2197 Registration.IsPublic =
false;
2198 Registration.Owner =
string.
Empty;
2203 await SaveNewRegistrationTags(
Registration, this.GetArray(Tags));
2211 catch (Exception ex)
2217 private async Task<Registration> GetRegistration(
CaseInsensitiveString JID,
string NodeId,
string SourceId,
string Partition,
2229 bool Updated =
false;
2231 if (ThingVersion.HasValue && Result.Version != ThingVersion.Value)
2233 Result.Version = ThingVersion.Value;
2237 if (OwnerVersion.HasValue && Result.OwnerVersion != OwnerVersion.Value)
2239 Result.OwnerVersion = OwnerVersion.Value;
2249 private MetaDataTag[] GetArray(Dictionary<string, MetaDataTag> Tags)
2252 Tags.Values.CopyTo(Result, 0);
2256 private static KeyValuePair<string, object>[] GetLogParameters(
ThingReference Node, IEnumerable<MetaDataTag> Tags)
2258 List<KeyValuePair<string, object>> Result =
new List<KeyValuePair<string, object>>();
2260 if (!
string.IsNullOrEmpty(Node.
NodeId))
2261 Result.Add(
new KeyValuePair<string, object>(
"NodeId", Node.
NodeId));
2263 if (!
string.IsNullOrEmpty(Node.
SourceId))
2264 Result.Add(
new KeyValuePair<string, object>(
"SourceId", Node.
SourceId));
2266 if (!
string.IsNullOrEmpty(Node.
Partition))
2267 Result.Add(
new KeyValuePair<string, object>(
"Partition", Node.
Partition));
2269 if (!(Tags is
null))
2272 Result.Add(
new KeyValuePair<string, object>(Tag.
Name, Tag.
Value));
2275 return Result.ToArray();
2278 private static KeyValuePair<string, object>[] GetLogParameters(
Registration Node, IEnumerable<MetaDataTag> Tags)
2280 List<KeyValuePair<string, object>> Result =
new List<KeyValuePair<string, object>>();
2282 if (!
string.IsNullOrEmpty(Node.
NodeId))
2283 Result.Add(
new KeyValuePair<string, object>(
"NodeId", Node.
NodeId));
2285 if (!
string.IsNullOrEmpty(Node.
SourceId))
2286 Result.Add(
new KeyValuePair<string, object>(
"SourceId", Node.
SourceId));
2288 if (!
string.IsNullOrEmpty(Node.
Partition))
2289 Result.Add(
new KeyValuePair<string, object>(
"Partition", Node.
Partition));
2292 Result.Add(
new KeyValuePair<string, object>(Tag.
Name, Tag.
Value));
2294 return Result.ToArray();
2297 private async Task UpdateHandler(
object _,
IqEventArgs e)
2301 XmlElement E = e.
Query;
2306 Node = this.ParseNodeInfo(E);
2307 if (!this.ParseTags(e, E, out Dictionary<string, MetaDataTag> Tags, out
string Key))
2321 await e.
IqResult(
"<disowned xmlns='" + e.
Query.NamespaceURI +
"'/>", e.
To);
2336 Registration.LastUpdate = DateTime.Now;
2339 await UpdateRegistrationTags(
Registration, this.GetArray(Tags));
2344 "Update", GetLogParameters(Node, Tags.Values));
2347 await IncAccountSuccessfulUpdates(e.
From.
BareJid);
2350 catch (Exception ex)
2368 private async Task UnregisterHandler(
object _,
IqEventArgs e)
2372 XmlElement E = e.
Query;
2375 Node = this.ParseNodeInfo(E);
2386 await this.DeleteRules(R);
2393 catch (Exception ex)
2411 private async Task MineHandler(
object _,
IqEventArgs e)
2413 XmlElement E = e.
Query;
2416 if (!this.ParseTags(e, E, out Dictionary<string, MetaDataTag> Tags, out
string Key))
2422 if (
string.IsNullOrEmpty(Key))
2430 IEnumerable<MetaDataTag> MatchTags;
2461 if (!Match || c != Tags.Count)
2467 R.Key =
string.Empty;
2469 R.IsPublic = Public;
2476 Tag.IsPublic = Public;
2486 StringBuilder Response =
new StringBuilder();
2488 Response.Append(
"<claimed xmlns='");
2489 Response.Append(e.
Query.NamespaceURI);
2490 Response.Append(
"' jid='");
2493 if (!
string.IsNullOrEmpty(R.
NodeId))
2495 Response.Append(
"' id='");
2499 if (!
string.IsNullOrEmpty(R.
SourceId))
2501 Response.Append(
"' src='");
2507 Response.Append(
"' pt='");
2511 Response.Append(
"'/>");
2519 Response.Append(
"<claimed xmlns='");
2520 Response.Append(NamespaceIoTDiscovery(R.Version));
2521 Response.Append(
"' jid='");
2523 Response.Append(
"' public='");
2526 if (!
string.IsNullOrEmpty(R.
NodeId))
2528 Response.Append(
"' id='");
2532 if (!
string.IsNullOrEmpty(R.
SourceId))
2534 Response.Append(
"' src='");
2540 Response.Append(
"' pt='");
2544 Response.Append(
"'/>");
2546 await this.Server.GetLastPresence(R.
JID, async (sender, e2) =>
2549 await
this.Server.SendIqRequest(
"set", e.
To, e2.From,
string.
Empty, Response.
ToString(),
null,
null);
2563 List<MetaDataTag> Tags =
new List<MetaDataTag>();
2568 return Tags.ToArray();
2585 private static Task<IEnumerable<MetaDataTag>> LoadTags(Guid RegistrationReference)
2592 Dictionary<string, MetaDataTag> Tags2 =
new Dictionary<string, MetaDataTag>(StringComparer.CurrentCultureIgnoreCase);
2595 Tags2[Tag.
Name] = Tag;
2597 if (!(Tags is
null))
2606 Tags2.Remove(Tag.
Name);
2610 Tag.ObjectId = Tag2.ObjectId;
2636 return Tags2.Values;
2651 private async Task DisownHandler(
object _,
IqEventArgs e)
2655 XmlElement E = e.
Query;
2659 Node = this.ParseNodeInfo(E);
2671 StringBuilder Request =
new StringBuilder();
2673 Request.Append(
"<disowned xmlns='");
2674 Request.Append(NamespaceIoTDiscovery(R.Version));
2675 AppendNodeReference(Request, Node);
2676 Request.Append(
"'/>");
2678 await this.Server.GetLastPresence(Jid, async (sender, e3) =>
2684 R.Key = Convert.ToBase64String(Gateway.NextBytes(16));
2686 R.Owner = string.Empty;
2688 await this.Server.SendIqRequest(
"set", e.To, e3.From, string.Empty,
2689 Request.ToString(), async (sender2, e4) =>
2695 await e.IqResult(string.Empty, e.To);
2697 IEnumerable<MetaDataTag> Tags = await LoadTags(R.ObjectId);
2699 await Database.StartBulk();
2702 await Database.UpdateLazy(R);
2703 await Database.DeleteLazy(Tags);
2704 await this.DeleteRules(R);
2708 await Database.EndBulk();
2711 Log.Informational(
"Thing disowned.", R.JID, Jid,
"Disown", GetLogParameters(Node, Tags));
2713 await IncAccountSuccessfulDisownments(e.From.BareJid);
2716 await e.IqErrorNotAllowed(e.To,
"Thing needs to accept disownment.",
"en");
2718 catch (Exception ex)
2727 catch (Exception ex)
2736 await IncAccountFailedDisownments(e.
From.
BareJid);
2743 await IncAccountFailedDisownments(e.
From.
BareJid);
2745 catch (Exception ex)
2763 private async Task RemoveHandler(
object _,
IqEventArgs e)
2767 XmlElement E = e.
Query;
2771 Node = this.ParseNodeInfo(E);
2787 IEnumerable<MetaDataTag> Tags = await LoadTags(R.
ObjectId);
2789 Log.
Informational(
"Thing removed from public registry.", R.
JID, Jid,
"Remove", GetLogParameters(Node, Tags));
2794 StringBuilder Request =
new StringBuilder();
2796 Request.Append(
"<removed xmlns='");
2797 Request.Append(NamespaceIoTDiscovery(R.Version));
2798 AppendNodeReference(Request, Node);
2799 Request.Append(
"'/>");
2801 await this.Server.GetLastPresence(Jid, async (sender, e3) =>
2806 await
this.Server.SendIqRequest(
"set", e.
To, e3.From,
string.
Empty, Request.
ToString(),
null,
null);
2808 catch (Exception ex)
2814 await IncAccountSuccessfulRemovals(e.
From.
BareJid);
2828 catch (Exception ex)
2846 private async Task SearchHandler(
object _,
IqEventArgs e)
2850 XmlElement E = e.
Query;
2863 else if (MaxCount <= 0)
2869 List<SearchOperator> SearchOperators =
new List<SearchOperator>();
2871 object FirstEqualityValue =
null;
2874 foreach (XmlNode N
in E.ChildNodes)
2876 E2 = N as XmlElement;
2881 if (
string.IsNullOrEmpty(Name))
2889 await e.
IqResult(
"<found xmlns='" + e.
Query.NamespaceURI +
"' more='false'/>", e.
To);
2894 switch (E2.LocalName)
2899 SearchOperators.Add(StrOp);
2901 if (FirstEquality is
null)
2903 FirstEquality = StrOp;
2904 FirstEqualityValue = StrOp.
Value;
2957 SearchOperators.Add(NumOp);
2959 if (FirstEquality is
null)
2961 FirstEquality = NumOp;
2962 FirstEqualityValue = NumOp.
Value;
3003 await e.
IqResult(
"<found xmlns='" + e.
Query.NamespaceURI +
"' more='false'/>", e.
To);
3009 if (FirstEquality is
null)
3011 await e.
IqErrorBadRequest(e.
To,
"Too wide a search. Make sure to include at least one equality operator in the search to limit its scope.",
"en");
3017 List<KeyValuePair<Registration, IEnumerable<MetaDataTag>>> Result =
new List<KeyValuePair<Registration, IEnumerable<MetaDataTag>>>();
3018 Dictionary<string, MetaDataTag> TagsSorted =
new Dictionary<string, MetaDataTag>(StringComparer.CurrentCultureIgnoreCase);
3019 IEnumerable<MetaDataTag> Tags;
3029 TagsSorted[Tag2.
Name] = Tag2;
3046 else if (Result.Count == MaxCount)
3057 Result.Add(
new KeyValuePair<
Registration, IEnumerable<MetaDataTag>>(R, Tags));
3062 await e.
IqResult(ResultSet(Result, More, e.
Query.NamespaceURI), e.
To);
3064 await IncAccountSuccessfulSearches(e.
From.
BareJid, Result.Count);
3066 catch (Exception ex)
3073 public static string ResultSet(List<KeyValuePair<
Registration, IEnumerable<MetaDataTag>>> Result,
bool More,
string Namespace)
3075 StringBuilder Response =
new StringBuilder();
3077 Response.Append(
"<found xmlns='");
3078 Response.Append(Namespace);
3079 Response.Append(
"' more='");
3081 Response.Append(
"'>");
3083 foreach (KeyValuePair<
Registration, IEnumerable<MetaDataTag>> P
in Result)
3085 Response.Append(
"<thing jid='");
3088 if (!
string.IsNullOrEmpty(P.Key.NodeId))
3090 Response.Append(
"' id='");
3091 Response.Append(
XML.
Encode(P.Key.NodeId));
3094 if (!
string.IsNullOrEmpty(P.Key.SourceId))
3096 Response.Append(
"' src='");
3097 Response.Append(
XML.
Encode(P.Key.SourceId));
3100 if (!
string.IsNullOrEmpty(P.Key.Partition))
3102 Response.Append(
"' pt='");
3103 Response.Append(
XML.
Encode(P.Key.Partition));
3106 Response.Append(
"'>");
3108 if (!(P.Value is
null))
3114 Response.Append(
"<str name='");
3116 Response.Append(
"' value='");
3117 Response.Append(
XML.
Encode(StrTag.TagValue));
3118 Response.Append(
"'/>");
3122 Response.Append(
"<num name='");
3124 Response.Append(
"' value='");
3126 Response.Append(
"'/>");
3131 Response.Append(
"</thing>");
3134 Response.Append(
"</found>");
3136 return Response.ToString();
3143 Account.NrSearchResultItems += NrItems;
3158 if (
string.IsNullOrEmpty(NodeId) &&
string.IsNullOrEmpty(SourceId) &&
string.IsNullOrEmpty(Partition))
3164 private bool ParseTags(
IqEventArgs e, XmlElement E, out Dictionary<string, MetaDataTag> Tags, out
string Key)
3168 Tags =
new Dictionary<string, MetaDataTag>();
3171 foreach (XmlNode N
in E.ChildNodes)
3173 E2 = N as XmlElement;
3178 if (Name.Length > 32)
3190 foreach (
char ch
in Name)
3192 if (ch ==
':' || ch ==
'#' ||
char.IsWhiteSpace(ch))
3199 switch (N.LocalName)
3203 if (Value.Length > 128)
3224 internal static void AppendNodeReference(StringBuilder Request,
ThingReference Node)
3226 if (!
string.IsNullOrEmpty(Node.
NodeId))
3228 Request.Append(
"' id='");
3232 if (!
string.IsNullOrEmpty(Node.
SourceId))
3234 Request.Append(
"' src='");
3238 if (!
string.IsNullOrEmpty(Node.
Partition))
3240 Request.Append(
"' pt='");
3245 private async Task DeleteRulesHandler(
object Sender,
IqEventArgs e)
3257 Dictionary<CaseInsensitiveString, NamespaceSet> Jids =
new Dictionary<CaseInsensitiveString, NamespaceSet>();
3261 await this.DeleteRules(R);
3262 Jids[R.
JID] = R.Version;
3265 foreach (KeyValuePair<CaseInsensitiveString, NamespaceSet> P
in Jids)
3266 await this.ClearCache(P.Key, P.Value);
3283 await this.DeleteRules(R);
3284 await this.ClearCache(Jid, R.Version);
3289 catch (Exception ex)
3297 #region Software Updates
3299 private async Task GetPackageInfoHandler(
object Sender,
IqEventArgs e)
3307 StringBuilder Xml =
new StringBuilder();
3308 Serialize(
Package, Xml, QueryVersion);
3314 if (!this.Server.IsServerDomain(e.
From.
Domain,
true))
3325 if (!this.CheckSameDomain(e))
3341 string FullFileName = Path.Combine(
XmppServerModule.PackagesFolder, FileName);
3342 if (!File.Exists(FullFileName))
3352 private static readonly Dictionary<CaseInsensitiveString, Package> packages =
new Dictionary<CaseInsensitiveString, Package>();
3353 private static bool packagesLoaded =
false;
3361 if (!packages.TryGetValue(FileName, out
Package))
3382 Serialize(
Package,
"packageInfo", Xml, Version);
3388 Xml.Append(LocalName);
3389 Xml.Append(
" fileName='");
3391 Xml.Append(
"' signature='");
3393 Xml.Append(
"' published='");
3398 Xml.Append(
"' supersedes='");
3402 Xml.Append(
"' created='");
3404 Xml.Append(
"' url='");
3406 Xml.Append(
"' bytes='");
3409 if (Version.HasValue)
3411 Xml.Append(
"' xmlns='");
3412 Xml.Append(NamespaceSoftwareUpdates(Version.Value));
3418 private async Task GetPackagesHandler(
object Sender,
IqEventArgs e)
3420 StringBuilder Xml =
new StringBuilder();
3422 Xml.Append(
"<packages xmlns='");
3423 Xml.Append(e.
Query.NamespaceURI);
3429 if (!File.Exists(FullFileName))
3432 Serialize(
Package, Xml,
null);
3435 Xml.Append(
"</packages>");
3440 public static async Task<Package[]> GetPackages()
3442 if (!packagesLoaded)
3452 packagesLoaded =
true;
3458 packages.Values.CopyTo(Result, 0);
3472 StringBuilder Xml =
new StringBuilder();
3473 Serialize(
Package, Xml, Version);
3474 return Xml.ToString();
3477 await this.Notify(
Package, Serializer);
3478 await this.Notify(
null, Serializer);
3490 StringBuilder Xml =
new StringBuilder();
3492 Xml.Append(
"<packageDeleted fileName='");
3494 Xml.Append(
"' xmlns='");
3495 Xml.Append(NamespaceSoftwareUpdates(Version));
3498 return Xml.ToString();
3501 await this.Notify(
Package, Serializer);
3502 await this.Notify(
null, Serializer);
3505 private delegate
string SerializePackageDelegate(
NamespaceSet Version);
3507 private async Task Notify(
Package Package, SerializePackageDelegate Serializer)
3509 Dictionary<CaseInsensitiveString, bool> Sent =
new Dictionary<CaseInsensitiveString, bool>();
3514 if (
string.Compare(Notification.BareJid,
Gateway.
XmppClient.BareJID,
true) == 0)
3520 if (!Sent.ContainsKey(To.
Address))
3522 string Xml = Serializer(Notification.Version);
3529 private async Task SubscribeHandler(
object Sender,
IqEventArgs e)
3531 if (!this.CheckSameDomain(e))
3537 if (FileName ==
"*")
3539 LinkedList<object> ToDelete =
null;
3544 if (Notification.FileName == FileName)
3548 if (ToDelete is
null)
3549 ToDelete =
new LinkedList<object>();
3551 ToDelete.AddLast(Notification);
3559 FileName = FileName,
3562 Version = QueryVersion
3568 if (!(ToDelete is
null))
3584 if (Notification is
null)
3593 await e.
IqErrorNotAllowed(e.
To,
"Maximum number of subscriptions reached. Either unsubscribe, or use a wildcard subscription.",
"en");
3599 FileName = FileName,
3602 Version = QueryVersion
3612 private async Task UnsubscribeHandler(
object Sender,
IqEventArgs e)
3614 if (!this.CheckSameDomain(e))
3619 if (FileName ==
"*")
3630 if (!(Notification is
null))
3638 private async Task GetSubscriptionsHandler(
object Sender,
IqEventArgs e)
3640 if (!this.CheckSameDomain(e))
3643 StringBuilder Xml =
new StringBuilder();
3645 Xml.Append(
"<subscriptions xmlns='");
3646 Xml.Append(e.
Query.NamespaceURI);
3652 Xml.Append(
"<subscription>");
3653 Xml.Append(
XML.
Encode(Notification.FileName));
3654 Xml.Append(
"</subscription>");
3657 Xml.Append(
"</subscriptions>");
Helps with parsing of commong data types.
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Helps with common XML-related tasks.
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
static string Encode(string s)
Encodes a string for use in XML.
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
Static class managing the runtime environment of the IoT Gateway.
static DateTime ScheduleEvent(ScheduledEventCallback Callback, DateTime When, object State)
Schedules a one-time event.
static XmppClient XmppClient
XMPP Client connection of gateway.
Base class for components.
void RegisterIqSetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool PublishNamespaceAsFeature)
Registers an IQ-Set handler.
CaseInsensitiveString Subdomain
Subdomain name.
void RegisterIqGetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool PublishNamespaceAsFeature)
Registers an IQ-Get handler.
string Name
Component name.
readonly object synchObject
Synchronization object for thread-safe access to internal structures.
bool IsComponentDomain(CaseInsensitiveString Domain, bool IncludeAlternativeDomains)
Checks if a domain is the component domain, or optionally, an alternative component domain.
XmppServer Server
XMPP Server.
bool UnregisterIqGetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool RemoveNamespaceAsFeature)
Unregisters an IQ-Get handler.
bool UnregisterIqSetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool RemoveNamespaceAsFeature)
Unregisters an IQ-Set handler.
Event arguments for IQ queries.
XmppAddress From
From address attribute
Task IqErrorNotAcceptable(XmppAddress From, string ErrorText, string Language)
Returns a not-acceptable error.
Task IqResult(string Xml, string From)
Returns a response to the current request.
Task IqErrorItemNotFound(XmppAddress From, string ErrorText, string Language)
Returns a item-not-found error.
XmlElement Query
Query element, if found, null otherwise.
Task IqErrorNotAllowed(XmppAddress From, string ErrorText, string Language)
Returns a not-allowed error.
XmppAddress To
To address attribute
async Task IqError(string ErrorType, string Xml, XmppAddress From, string ErrorText, string Language)
Returns an error response to the current request.
Task IqErrorBadRequest(XmppAddress From, string ErrorText, string Language)
Returns a bad-request error.
Task IqErrorForbidden(XmppAddress From, string ErrorText, string Language)
Returns a forbidden error.
Event arguments for responses to IQ queries.
object State
State object passed to the original request.
XmppAddress From
From address attribute
XmlElement FirstElement
First child element of the Response element.
bool Ok
If the response is an OK result response (true), or an error response (false).
Contains information about one XMPP address.
override string ToString()
object.ToString()
bool IsEmpty
If the address is empty.
CaseInsensitiveString Domain
Domain
CaseInsensitiveString Address
XMPP Address
CaseInsensitiveString BareJid
Bare JID
static readonly XmppAddress Empty
Empty address.
Task< bool > SendMessage(string Type, string Id, string From, string To, string Language, string ContentXml)
Sends a Message stanza to a recipient.
static byte[] GetRandomNumbers(int NrBytes)
Generates a set of random numbers.
Represents a case-insensitive string.
string Value
String-representation of the case-insensitive string. (Representation is case sensitive....
static readonly CaseInsensitiveString Empty
Empty case-insensitive string
int IndexOf(CaseInsensitiveString value, StringComparison comparisonType)
Reports the zero-based index of the first occurrence of the specified string in the current System....
static bool IsNullOrEmpty(CaseInsensitiveString value)
Indicates whether the specified string is null or an CaseInsensitiveString.Empty string.
CaseInsensitiveString Substring(int startIndex, int length)
Retrieves a substring from this instance. The substring starts at a specified character position and ...
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task< IEnumerable< object > > FindDelete(string Collection, params string[] SortOrder)
Finds objects in a given collection and deletes them in the same atomic operation.
static async Task DeleteLazy(object Object)
Deletes an object in the database, if unlocked. If locked, object will be deleted at next opportunity...
static Task EndBulk()
Ends bulk-processing of data. Must be called once for every call to StartBulk.
static async Task InsertLazy(object Object)
Inserts an object into the database, if unlocked. If locked, object will be inserted at next opportun...
static Task StartBulk()
Starts bulk-proccessing of data. Must be followed by a call to EndBulk.
static async Task UpdateLazy(object Object)
Updates an object in the database, if unlocked. If locked, object will be updated at next opportunity...
static async Task Update(object Object)
Updates an object in the database.
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
static Task< object > TryLoadObject(string CollectionName, object ObjectId)
Tries to load an object given its Object ID ObjectId and its collection name CollectionName .
This filter selects objects that conform to all child-filters provided.
This filter selects objects that have a named field equal to a given value.
Implements an in-memory cache.
bool ContainsKey(KeyType Key)
Checks if a key is available in the cache.
void Dispose()
IDisposable.Dispose
bool Remove(KeyType Key)
Removes an item from the cache.
bool TryGetValue(KeyType Key, out ValueType Value)
Tries to get a value from the cache.
void Add(KeyType Key, ValueType Value)
Adds an item to the cache.
void Clear()
Clears the cache.
Event arguments for cache item removal events.
ValueType Value
Value of item that was removed.
Provisioning and registry service component.
const string NamespaceProvisioningOwnerIeeeV1
urn:ieee:iot:prov:o:1.0
async Task ClearCache(CaseInsensitiveString BareJid, NamespaceSet Version)
Notifies the entity its rule cache should be cleared.
const string NamespaceSoftwareUpdatesNeuroFoundationV1
urn:nf:iot:swu:1.0
const string NamespaceProvisioningTokenNeuroFoundationV1
urn:nf:iot:prov:t:1.0
static string NamespaceProvisioningOwner(NamespaceSet Version)
Returns the namespace for owner provisioning.
static string NamespaceSoftwareUpdates(NamespaceSet Version)
Returns the namespace for Software Updates.
static string NamespaceProvisioningToken(NamespaceSet Version)
Returns the namespace for token provisioning.
bool TryGetCertificate(string Token, out X509Certificate2 Certificate)
Tries to get a certificate for a given token.
const string NamespaceIoTDiscoveryNeuroFoundationV1
urn:nf:iot:disco:1.0
const string NamespaceProvisioningTokenIeeeV1
urn:ieee:iot:prov:t:1.0
ProvisioningComponent(XmppServer Server, CaseInsensitiveString Subdomain, string Name)
Provisioning and registry service component.
const string NamespaceProvisioningDeviceIeeeV1
urn:ieee:iot:prov:d:1.0
override bool SupportsAccounts
If the component supports accounts (true), or if the subdomain name is the only valid address.
const string NamespaceIoTDiscoveryIeeeV1
urn:ieee:iot:disco:1.0
static string NamespaceIoTDiscovery(NamespaceSet Version)
Returns the namespace for IoT Discovery.
static string NamespaceProvisioningDevice(NamespaceSet Version)
Returns the namespace for device provisioning.
async Task RecommendBefriend(CaseInsensitiveString BareJid1, CaseInsensitiveString BareJid2, NamespaceSet Version)
Notifies the entity identified by BareJid1 , that it should befriend (subscribe to presence from) the...
override void Dispose()
IDisposable.Dispose
async Task RecommendUnfriend(CaseInsensitiveString BareJid1, CaseInsensitiveString BareJid2, NamespaceSet Version)
Notifies the entity identified by BareJid1 , that it should remove friendship (presence subscription ...
const string NamespaceIoTDiscoveryXsfV0
urn:xmpp:iot:discovery
const string NamespaceProvisioningOwnerNeuroFoundationV1
urn:nf:iot:prov:o:1.0
const string NamespaceSoftwareUpdatesIeeeV1
urn:ieee:iot:swu:1.0
const string NamespaceProvisioningDeviceNeuroFoundationV1
urn:nf:iot:prov:d:1.0
Guid ObjectId
Persisted object ID. Is null if object not persisted.
CaseInsensitiveString JID
JID.
int NrRegistrations
Number of registrations made.
string Partition
Optional partition in which the Node ID is unique.
string SourceId
Optional ID of source containing node.
DateTime FirstRegistration
Timestamp of first registration.
int NrUpdates
Number of updates made.
CaseInsensitiveString Owner
Secret key
long NrSuccessfulDisownments
Number of successful disownments.
long NrSuccessfulClaims
Number of successful claims.
long NrSuccessfulUpdates
Number of successful updates.
long NrFailedSearches
Number of failed searches.
long NrFailedRemovals
Number of failed removals.
long NrFailedUpdates
Number of failed updates.
long NrSuccessfulRemovals
Number of successful removals.
long NrFailedClaims
Number of failed claims.
long NrSuccessfulSearches
Number of successful searches.
long NrFailedDisownments
Number of failed disownments.
Controls if a device with a remote JID is allowed to control a device with JID.
Controls if a device with a remote JID is allowed to subscribe to the presence of a device with JID.
Controls if a device with a remote JID is allowed to read data from a device with JID.
Abstract base class for rules.
void AddChildRule(Rule Rule)
Adds a child rule.
virtual ? bool Evaluate(Context Context)
Tries to evaluate the rule.
Filters things with a named numeric-valued tag equal to a given value.
Filters things with a named numeric-valued tag greater than a given value.
Filters things with a named numeric-valued tag greater than or equal to a given value.
Filters things with a named numeric-valued tag within a given range.
Filters things with a named numeric-valued tag lesser than a given value.
Filters things with a named numeric-valued tag lesser than or equal to a given value.
Filters things with a named numeric-valued tag not equal to a given value.
Filters things with a named numeric-valued tag outside a given range.
Abstract base class for all search operators.
abstract bool AppliesTo(MetaDataTag Tag)
Checks if the operator applies to a tag.
Filters things with a named string-valued tag equal to a given value.
Filters things with a named string-valued tag greater than a given value.
Filters things with a named string-valued tag greater than or equal to a given value.
Filters things with a named string-valued tag within a given range.
Filters things with a named string-valued tag lesser than a given value.
Filters things with a named string-valued tag lesser than or equal to a given value.
Filters things with a named string-valued tag like a given value.
Filters things with a named string-valued tag not equal to a given value.
Filters things with a named string-valued tag outside a given range.
Filters things with a named string-valued tag matching a regular expression.
Contains information about a software package.
byte[] Signature
Cryptographic signature of package, as calculated by the issuer of the package.
CaseInsensitiveString FileName
Filename of package.
DateTime Published
When package was published.
string Url
URL of package.
long Bytes
Number of bytes of package.
DateTime Supersedes
Timestamp of superceded package.
DateTime Created
When package record was created
Service Module hosting the XMPP broker and its components.
static NamespaceSet GetVersion(string Namespace)
Gets the namespace set version corresponding to a given a namespace.
Base class for all sensor data fields.
Contains a reference to a thing
static ThingReference Empty
Empty thing reference. Can be used by sensors that are not part of a concentrator during readout.
string Partition
Optional partition in which the Node ID is unique.
bool IsEmpty
If the reference is an empty reference.
string SourceId
Optional ID of source containing node.
RuleRange
Range of a rule change
NamespaceSet
Namespace versions
FieldType
Field Type flags