private static bool HandleAuthentication(ClientStateInfo clientInfo, TcpClient client, SharedNetwork.SharedNetworkInfo sharedInfo) { if (Config.RequiresAuthentication) { int flags = ((Config.AllowUnauthenticatedWrite ? 2 : 0) | (Config.AllowUnauthenticatedRead ? 1 : 0)); if (clientInfo.BareAccessRequired) flags = 0; ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.Authenticate, Identifier = flags }, ProtoBuf.PrefixStyle.Fixed32); AuthenticationChallenge challenge = new AuthenticationChallenge(); challenge.AvailableModes = new List<AuthenticationMode>(); if (Config.SupportsSimpleAuthentication) challenge.AvailableModes.Add(AuthenticationMode.Simple); challenge.Salt = BCrypt.Net.BCrypt.GenerateSalt(); ProtoBuf.Serializer.SerializeWithLengthPrefix(client.GetStream(), challenge, ProtoBuf.PrefixStyle.Fixed32); int retries = Config.AuthenticationAttempts; bool success = false; while (true) { var response = ProtoBuf.Serializer.DeserializeWithLengthPrefix<AuthenticationResponse>(client.GetStream(), ProtoBuf.PrefixStyle.Fixed32); Rights accessRights; if (CheckAuthentication(response, challenge.Salt, out accessRights)) { clientInfo.Access = accessRights; success = true; break; } else { if (--retries == 0) break; ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.AuthRetry }, ProtoBuf.PrefixStyle.Fixed32); } } if (success) ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.Acknowledge }, ProtoBuf.PrefixStyle.Fixed32); else { ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.AuthFail }, ProtoBuf.PrefixStyle.Fixed32); return false; } } else { ProtoBuf.Serializer.SerializeWithLengthPrefix<NetCommand>(client.GetStream(), new NetCommand() { Type = NetCommandType.SkipAuthentication }, ProtoBuf.PrefixStyle.Fixed32); } return true; }
internal static void GetAncestryInternal(HashSet<Guid> checkedVersions, Guid version, SharedNetwork.SharedNetworkInfo clientInfo) { Guid nextVersionToCheck = version; while (nextVersionToCheck != null) { if (checkedVersions.Contains(nextVersionToCheck)) return; checkedVersions.Add(nextVersionToCheck); List<MergeInfo> mergeInfo; Objects.Version v = FindLocalOrRemoteVersionInfo(nextVersionToCheck, clientInfo, out mergeInfo); foreach (var x in mergeInfo) { GetAncestryInternal(checkedVersions, x.SourceVersion, clientInfo); } if (!v.Parent.HasValue) return; nextVersionToCheck = v.Parent.Value; } }
private static void ReceiveRecordParents(SharedNetwork.SharedNetworkInfo sharedInfo, RecordParentPack response) { foreach (var x in response.Parents) { CheckRecord(sharedInfo, x); } }
internal static bool IsAncestorInternal(HashSet<Guid> checkedVersions, Guid ancestor, Guid possibleChild, SharedNetwork.SharedNetworkInfo clientInfo) { Guid nextVersionToCheck = possibleChild; if (ancestor == possibleChild) return true; while (true) { if (checkedVersions.Contains(nextVersionToCheck)) return false; checkedVersions.Add(nextVersionToCheck); List<MergeInfo> mergeInfo; Objects.Version v = FindLocalOrRemoteVersionInfo(nextVersionToCheck, clientInfo, out mergeInfo); if (!v.Parent.HasValue) return false; else if (v.Parent.Value == ancestor) return true; foreach (var x in mergeInfo) { if (IsAncestorInternal(checkedVersions, ancestor, x.SourceVersion, clientInfo)) return true; } nextVersionToCheck = v.Parent.Value; } }
internal static Objects.Version FindLocalOrRemoteVersionInfo(Guid possibleChild, SharedNetwork.SharedNetworkInfo clientInfo, out List<MergeInfo> mergeInfo) { VersionInfo info = clientInfo.PushedVersions.Where(x => x.Version.ID == possibleChild).FirstOrDefault(); if (info != null) { mergeInfo = info.MergeInfos != null ? info.MergeInfos.ToList() : new List<MergeInfo>(); return info.Version; } Objects.Version localVersion = clientInfo.Workspace.GetVersion(possibleChild); mergeInfo = clientInfo.Workspace.GetMergeInfo(localVersion.ID).ToList(); return localVersion; }
internal static void ImportBranches(SharedNetwork.SharedNetworkInfo sharedInfo) { Printer.PrintDiagnostics("Received branches:"); foreach (var x in sharedInfo.ReceivedBranches) { Printer.PrintDiagnostics(" - {0}: \"{1}\"", x.ID, x.Name); sharedInfo.Workspace.ImportBranchNoCommit(x); } Printer.PrintDiagnostics("Branches imported."); }
internal static bool IsAncestor(Guid ancestor, Guid possibleChild, SharedNetwork.SharedNetworkInfo clientInfo) { HashSet<Guid> checkedVersions = new HashSet<Guid>(); return IsAncestorInternal(checkedVersions, ancestor, possibleChild, clientInfo); }
private bool PullVersions(SharedNetwork.SharedNetworkInfo sharedInfo, out bool receivedData) { bool importResult = sharedInfo.Workspace.RunLocked(() => { return SharedNetwork.ImportRecords(sharedInfo, true); }, false); receivedData = false; if (!importResult) return false; if (sharedInfo.PushedVersions.Count == 0 && sharedInfo.ReceivedBranchJournals.Count == 0 && sharedInfo.ReceivedBranches.Count == 0) return true; receivedData = true; return sharedInfo.Workspace.RunLocked(() => { lock (sharedInfo.Workspace) { try { sharedInfo.Workspace.BeginDatabaseTransaction(); if (!SharedNetwork.ImportBranchJournal(sharedInfo, true)) return false; SharedNetwork.ImportBranches(sharedInfo); Dictionary<Guid, List<Head>> temporaryHeads = new Dictionary<Guid, List<Head>>(); Dictionary<Guid, Guid> pendingMerges = new Dictionary<Guid, Guid>(); Dictionary<Guid, HashSet<Guid>> headAncestry = new Dictionary<Guid, HashSet<Guid>>(); HashSet<Guid> terminatedBranches = new HashSet<Guid>(); List<Guid> mergeResults = new List<Guid>(); foreach (var x in ((IEnumerable<VersionInfo>)sharedInfo.PushedVersions).Reverse()) { if (terminatedBranches.Contains(x.Version.Branch)) continue; List<Head> heads; if (!temporaryHeads.TryGetValue(x.Version.Branch, out heads)) { Branch branch = sharedInfo.Workspace.GetBranch(x.Version.Branch); if (branch.Terminus.HasValue) { terminatedBranches.Add(branch.ID); continue; } heads = new List<Head>(); var bheads = sharedInfo.Workspace.GetBranchHeads(branch); if (bheads.Count == 0) heads.Add(new Head() { Branch = branch.ID, Version = x.Version.ID }); else { foreach (var h in bheads) heads.Add(h); } temporaryHeads[branch.ID] = heads; } mergeResults.Clear(); for (int i = 0; i < heads.Count; i++) { if (heads[i].Version != x.Version.ID) { HashSet<Guid> headAncestors = null; if (!headAncestry.TryGetValue(heads[i].Version, out headAncestors)) { headAncestors = SharedNetwork.GetAncestry(heads[i].Version, sharedInfo); headAncestry[heads[i].Version] = headAncestors; } if (headAncestors.Contains(x.Version.ID)) { // all best mergeResults.Add(heads[i].Version); } else if (SharedNetwork.IsAncestor(heads[i].Version, x.Version.ID, sharedInfo)) { mergeResults.Add(x.Version.ID); } else { mergeResults.Add(Guid.Empty); } } } pendingMerges[x.Version.Branch] = Guid.Empty; // Remove any superceded heads // Add a merge if required bool unrelated = true; for (int i = 0; i < mergeResults.Count; i++) { if (mergeResults[i] == Guid.Empty) continue; else if (mergeResults[i] != heads[i].Version) { headAncestry.Remove(heads[i].Version); heads[i].Version = x.Version.ID; unrelated = false; } else unrelated = false; } if (unrelated) { heads.Add(new Head() { Branch = x.Version.Branch, Version = x.Version.ID }); } for (int i = 0; i < heads.Count; i++) { for (int j = i + 1; j < heads.Count; j++) { if (heads[i].Version == heads[j].Version) { heads.RemoveAt(j); --j; } } } } List<Head> newHeads = new List<Head>(); List<VersionInfo> autoMerged = new List<VersionInfo>(); foreach (var x in pendingMerges) { Branch branch = sharedInfo.Workspace.GetBranch(x.Key); List<Head> heads = temporaryHeads[x.Key]; var bheads = sharedInfo.Workspace.GetBranchHeads(branch); bool headsChanged = bheads.Count != heads.Count; if (!headsChanged) { for (int i = 0; i < bheads.Count; i++) { if (bheads[i].Version != heads[i].Version) headsChanged = true; } } if (!headsChanged) { temporaryHeads[x.Key] = null; continue; } if (heads.Count == 1) { Printer.PrintDiagnostics("Uncontested head update for branch \"{0}\".", Workspace.GetBranch(x.Key).Name); Printer.PrintDiagnostics(" - Head updated to {0}", temporaryHeads[x.Key][0].Version); continue; } var localVersions = bheads.Where(h => heads.Any(y => y.Version != h.Version)); var remoteVersions = heads.Where(h => !bheads.Any(y => y.Version != h.Version)); if (localVersions.Count() != 1) { Printer.PrintDiagnostics("Too many heads in local branch to merge remote head. Please merge locally and try again to update branch \"{0}\".", Workspace.GetBranch(x.Key).Name); return false; } Guid localVersion = localVersions.First().Version; if (remoteVersions.Count() == 1) { VersionInfo result; string error; result = Workspace.MergeRemote(Workspace.GetLocalOrRemoteVersion(localVersion, sharedInfo), remoteVersions.First().Version, sharedInfo, out error, true); Printer.PrintMessage("Resolved incoming merge for branch \"{0}\".", branch.Name); Printer.PrintDiagnostics(" - Merge local input {0}", localVersion); Printer.PrintDiagnostics(" - Merge remote input {0}", remoteVersions.First().Version); Printer.PrintDiagnostics(" - Head updated to {0}", result.Version.ID); for (int i = 0; i < heads.Count; i++) { if ((remoteVersions.Any() && heads[i].Version == remoteVersions.First().Version) || heads[i].Version == localVersion) { heads.RemoveAt(i); --i; } } heads.Add(new Head() { Branch = branch.ID, Version = result.Version.ID }); autoMerged.Add(result); } } var versionsToImport = sharedInfo.PushedVersions.OrderBy(x => x.Version.Timestamp).ToArray(); if (versionsToImport.Length != 0) { Dictionary<Guid, bool> importList = new Dictionary<Guid, bool>(); foreach (var x in versionsToImport) importList[x.Version.ID] = false; int importCount = versionsToImport.Length; var orderedImports = versionsToImport.OrderBy(x => x.Version.Revision).ToList(); Printer.InteractivePrinter printer = null; Printer.PrintMessage("Importing #b#{0}## versions...", orderedImports.Count); printer = Printer.CreateProgressBarPrinter("Importing", string.Empty, (obj) => { return string.Empty; }, (obj) => { return (100.0f * (int)(orderedImports.Count - importCount)) / (float)orderedImports.Count; }, (pct, obj) => { return string.Format("{0}/{1}", (int)(orderedImports.Count - importCount), orderedImports.Count); }, 60); while (importCount > 0) { foreach (var x in orderedImports) { if (importList[x.Version.ID] != true) { bool accept; if (!x.Version.Parent.HasValue || !importList.TryGetValue(x.Version.Parent.Value, out accept)) accept = true; if (accept) { sharedInfo.Workspace.ImportVersionNoCommit(sharedInfo, x, true); importList[x.Version.ID] = true; importCount--; printer.Update(importCount); } } } } printer.End(importCount); } Printer.PrintMessage("Updating internal state..."); foreach (var x in autoMerged) Workspace.ImportVersionNoCommit(sharedInfo, x, false); foreach (var x in temporaryHeads) { if (x.Value != null) Workspace.ReplaceHeads(x.Key, x.Value); } Workspace.CommitDatabaseTransaction(); sharedInfo.Workspace.CommitDatabaseTransaction(); return true; } catch { sharedInfo.Workspace.RollbackDatabaseTransaction(); throw; } } }, false); }
public static StartTransaction Create(string domain, SharedNetwork.Protocol protocol) { return new StartTransaction() { ServerHandshake = Handshake.Create(protocol), Domain = domain, Encrypted = false, Accepted = true }; }
public static StartTransaction Create(string domain, System.Security.Cryptography.RSAParameters publicKey, SharedNetwork.Protocol protocol) { return new StartTransaction() { ServerHandshake = Handshake.Create(protocol), Domain = domain, RSAKey = publicKey, Accepted = true, Encrypted = true }; }
public static Handshake Create(SharedNetwork.Protocol protocol) { return new Handshake() { VersionrProtocol = GetProtocolString(protocol) }; }
public static string GetProtocolString(SharedNetwork.Protocol protocol) { return Protocols[protocol]; }