/// <summary> /// Parses a path represented as a string. /// </summary> /// <param name="path">The string to parse.</param> /// <param name="result">The parsed <see cref="LedgerPath"/>.</param> /// <returns>A boolean indicating whether the value could be parsed successfully.</returns> public static bool TryParse(string path, out LedgerPath result) { result = null; if (path == null) { return(false); } string[] segments = path.Split('/'); if (segments.Length < 2 || segments[0] != string.Empty || segments[segments.Length - 1] != string.Empty) { return(false); } if (segments.Any(segment => !IsValidPathSegment(segment))) { return(false); } for (int i = 1; i < segments.Length - 1; i++) { if (segments[i] == string.Empty) { return(false); } } result = new LedgerPath(path, segments.Skip(1).Take(segments.Length - 2)); return(true); }
/// <summary> /// Parses a <see cref="ByteString"/> into an instance of a <see cref="RecordKey"/> object. /// </summary> /// <param name="keyData">The <see cref="ByteString"/> to parse.</param> /// <returns>The parsed <see cref="RecordKey"/>.</returns> public static RecordKey Parse(ByteString keyData) { if (keyData == null) { throw new ArgumentNullException(nameof(keyData)); } byte[] key = keyData.ToByteArray(); string[] parts = Encoding.UTF8.GetString(key, 0, key.Length).Split(new[] { ':' }, 3); if (parts.Length != 3) { throw new ArgumentOutOfRangeException(nameof(keyData)); } RecordKey result = ParseRecord( parts[1], LedgerPath.Parse(parts[0]), parts[2]); // The byte representation of reencoded value must match the input if (!result.ToBinary().Equals(keyData)) { throw new ArgumentOutOfRangeException(nameof(keyData)); } return(result); }
public async Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence> identities, LedgerPath path, bool recursiveOnly, string recordName) { PermissionSet currentPermissions = PermissionSet.Unset; Record record = await this.store.GetRecord(new RecordKey(RecordType.Data, path, AclResourceName)); if (record.Value.Value.Count == 0) return PermissionSet.Unset; IReadOnlyList<Acl> permissions; try { permissions = Acl.Parse(Encoding.UTF8.GetString(record.Value.ToByteArray()), path, keyEncoder); } catch (JsonReaderException) { return PermissionSet.Unset; } catch (NullReferenceException) { return PermissionSet.Unset; } foreach (Acl acl in permissions) { if (acl.IsMatch(identities, path, recursiveOnly, recordName)) currentPermissions = currentPermissions.Add(acl.Permissions); } return currentPermissions; }
public Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence> authentication, LedgerPath path, bool recursiveOnly, string recordName) { HashSet<string> identities = new HashSet<string>(authentication.Select(evidence => keyEncoder.GetPubKeyHash(evidence.PublicKey)), StringComparer.Ordinal); LedgerPath pathRecordName; // If the path is root and the record name is a tird-party asset owned by the current identity, // arbitrary modification of the balance is allowed if (LedgerPath.TryParse(recordName, out pathRecordName) && thirdPartyAssetPath.IsStrictParentOf(pathRecordName) && path.Segments.Count == 0 && identities.Contains(pathRecordName.Segments[thirdPartyAssetPath.Segments.Count])) { return Task.FromResult(new PermissionSet(accountNegative: Access.Permit)); } // Account /asset/p2pkh/[addr]/ if (thirdPartyAssetPath.IsStrictParentOf(path) && path.Segments.Count == thirdPartyAssetPath.Segments.Count + 1 && keyEncoder.IsP2pkh(path.Segments[path.Segments.Count - 1])) { Access ownAccount = identities.Contains(path.Segments[path.Segments.Count - 1]) && recordName != DynamicPermissionLayout.AclResourceName ? Access.Permit : Access.Unset; return Task.FromResult(new PermissionSet( accountModify: Access.Permit, accountCreate: Access.Permit, accountSpend: ownAccount, dataModify: ownAccount)); } else { return Task.FromResult(new PermissionSet()); } }
public Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence> authentication, LedgerPath path, bool recursiveOnly, string recordName) { PermissionSet currentPermissions = PermissionSet.Unset; foreach (Acl acl in permissions) { if (acl.IsMatch(authentication, path, recursiveOnly, recordName)) currentPermissions = currentPermissions.Add(acl.Permissions); } return Task.FromResult(currentPermissions); }
public static RecordKey ParseRecord(string recordType, LedgerPath ledgerPath, string name) { switch (recordType) { case "ACC": LedgerPath path = LedgerPath.Parse(name); return new RecordKey(RecordType.Account, ledgerPath, path.FullPath); case "DATA": return new RecordKey(RecordType.Data, ledgerPath, name); default: throw new ArgumentOutOfRangeException(nameof(recordType)); } }
public Acl( IEnumerable<IPermissionSubject> subjects, LedgerPath path, bool recursive, StringPattern recordName, PermissionSet permissions) { this.Subjects = subjects.ToList().AsReadOnly(); this.Path = path; this.Recursive = recursive; this.RecordName = recordName; this.Permissions = permissions; }
public static RecordKey ParseRecord(string recordType, LedgerPath ledgerPath, string name) { switch (recordType) { case "ACC": LedgerPath path = LedgerPath.Parse(name); return(new RecordKey(RecordType.Account, ledgerPath, path.FullPath)); case "DATA": return(new RecordKey(RecordType.Data, ledgerPath, name)); default: throw new ArgumentOutOfRangeException(nameof(recordType)); } }
public AccountKey(LedgerPath account, LedgerPath asset) { if (account == null) { throw new ArgumentNullException(nameof(account)); } if (asset == null) { throw new ArgumentNullException(nameof(asset)); } this.Account = account; this.Asset = asset; this.Key = new RecordKey(RecordType.Account, account, asset.FullPath); }
public bool IsParentOf(LedgerPath child) { if (child.Segments.Count < this.Segments.Count) { return(false); } for (int i = 0; i < this.Segments.Count; i++) { if (!StringComparer.Ordinal.Equals(this.Segments[i], child.Segments[i])) { return(false); } } return(true); }
/// <summary> /// Parses a permission set from a JSON string. /// </summary> /// <param name="json">The JSON string to parse.</param> /// <param name="path">The path on which these permissions apply.</param> /// <param name="keyEncoder">The key encoder to use in the parsed <see cref="Acl"/> objects.</param> /// <returns>The parsed list of <see cref="Acl"/> objects.</returns> public static IReadOnlyList<Acl> Parse(string json, LedgerPath path, KeyEncoder keyEncoder) { JArray document = JArray.Parse(json); return ((IEnumerable<JToken>)document).Select(root => new Acl( ((JArray)root["subjects"]).Children().Select(subject => new P2pkhSubject(((JArray)subject["addresses"]).Select(key => (string)key), (int)subject["required"], keyEncoder)), path, (bool?)root["recursive"] ?? true, new StringPattern((string)root["record_name"] ?? string.Empty, (PatternMatchingStrategy)Enum.Parse(typeof(PatternMatchingStrategy), (string)root["record_name_matching"] ?? "Prefix")), new PermissionSet( accountNegative: Parse(root["permissions"]["account_negative"]), accountSpend: Parse(root["permissions"]["account_spend"]), accountModify: Parse(root["permissions"]["account_modify"]), accountCreate: Parse(root["permissions"]["account_create"]), dataModify: Parse(root["permissions"]["data_modify"])))) .ToList(); }
/// <summary> /// Parses a path represented as a string. /// </summary> /// <param name="path">The string to parse.</param> /// <param name="result">The parsed <see cref="LedgerPath"/>.</param> /// <returns>A boolean indicating whether the value could be parsed successfully.</returns> public static bool TryParse(string path, out LedgerPath result) { result = null; if (path == null) return false; string[] segments = path.Split('/'); if (segments.Length < 2 || segments[0] != string.Empty || segments[segments.Length - 1] != string.Empty) return false; if (segments.Any(segment => !IsValidPathSegment(segment))) return false; for (int i = 1; i < segments.Length - 1; i++) if (segments[i] == string.Empty) return false; result = new LedgerPath(path, segments.Skip(1).Take(segments.Length - 2)); return true; }
public Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence> authentication, LedgerPath path, bool recursiveOnly, string recordName) { HashSet<string> identities = new HashSet<string>(authentication.Select(evidence => keyEncoder.GetPubKeyHash(evidence.PublicKey)), StringComparer.Ordinal); // Account /p2pkh/[addr]/ if (p2pkhAccountPath.IsStrictParentOf(path) && path.Segments.Count == p2pkhAccountPath.Segments.Count + 1 && keyEncoder.IsP2pkh(path.Segments[path.Segments.Count - 1])) { Access ownAccount = identities.Contains(path.Segments[path.Segments.Count - 1]) && recordName != DynamicPermissionLayout.AclResourceName ? Access.Permit : Access.Unset; return Task.FromResult(new PermissionSet( accountModify: Access.Permit, accountCreate: Access.Permit, accountSpend: ownAccount, dataModify: ownAccount)); } else { return Task.FromResult(new PermissionSet()); } }
/// <summary> /// Creates an instance of the <see cref="AccountStatus"/> class from an unparsed record. /// </summary> /// <param name="key">The key of the record.</param> /// <param name="record">The record to create the object from.</param> /// <returns>A new instance of the <see cref="AccountStatus"/> class.</returns> public static AccountStatus FromRecord(RecordKey key, Record record) { if (key.RecordType != RecordType.Account) { throw new ArgumentOutOfRangeException(nameof(key)); } long amount; if (record.Value.Value.Count == 0) { amount = 0; } else if (record.Value.Value.Count == 8) { amount = BitConverter.ToInt64(record.Value.Value.Reverse().ToArray(), 0); } else { throw new ArgumentOutOfRangeException(nameof(record)); } return(new AccountStatus(new AccountKey(key.Path, LedgerPath.Parse(key.Name)), amount, record.Version)); }
public RecordKey(RecordType recordType, LedgerPath path, string name) { this.RecordType = recordType; this.Path = path; this.Name = name; }
private async Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence> signedAddresses, LedgerPath path, string recordName) { PermissionSet accumulativePermissions = PermissionSet.DenyAll; for (int i = 0; i <= path.Segments.Count; i++) { bool recursiveOnly = i != path.Segments.Count; LedgerPath currentPath = LedgerPath.FromSegments(path.Segments.Take(i).ToArray()); PermissionSet[] permissions = await Task.WhenAll(this.permissions.Select(item => item.GetPermissions(signedAddresses, currentPath, recursiveOnly, recordName))); PermissionSet currentLevelPermissions = permissions .Aggregate(PermissionSet.Unset, (previous, current) => previous.Add(current)); accumulativePermissions = accumulativePermissions.AddLevel(currentLevelPermissions); } return accumulativePermissions; }
public bool IsParentOf(LedgerPath child) { if (child.Segments.Count < this.Segments.Count) return false; for (int i = 0; i < this.Segments.Count; i++) { if (!StringComparer.Ordinal.Equals(this.Segments[i], child.Segments[i])) return false; } return true; }
/// <summary> /// Creates a new instance of the <see cref="AccountKey"/> class from an account and asset. /// </summary> /// <param name="account">The account path.</param> /// <param name="asset">The asset path.</param> /// <returns>An instance of the <see cref="AccountKey"/> class representing the account and asset provided.</returns> public static AccountKey Parse(string account, string asset) { return(new AccountKey( LedgerPath.Parse(account), LedgerPath.Parse(asset))); }
/// <summary> /// Checks if the given parameters constitute a match for this <see cref="Acl"/> object. /// </summary> /// <param name="authentication">The signatures available.</param> /// <param name="path">The path of the record being tested.</param> /// <param name="recursiveOnly">Whether this object must be a recursive permission.</param> /// <param name="recordName">The name of the record being tested.</param> /// <returns>A boolean indicating whether the given parameters match.</returns> public bool IsMatch(IReadOnlyList<SignatureEvidence> authentication, LedgerPath path, bool recursiveOnly, string recordName) { return Path.FullPath == path.FullPath && (!recursiveOnly || Recursive) && RecordName.IsMatch(recordName) && Subjects.Any(subject => subject.IsMatch(authentication)); }
public Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence> identities, LedgerPath path, bool recursiveOnly, string recordName) { Assert.Equal(identities.Select(ConvertEvidence), expectedIdentities, StringComparer.Ordinal); PermissionSet result; if (!getPermissions.TryGetValue(path.FullPath, out result)) throw new InvalidOperationException(); else return Task.FromResult(result); }