示例#1
0
        /// <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);
        }
示例#2
0
        /// <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);
        }
示例#6
0
 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));
     }
 }
示例#7
0
 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;
 }
示例#8
0
        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));
            }
        }
示例#9
0
        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);
        }
示例#10
0
        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);
        }
示例#11
0
        /// <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();
        }
示例#12
0
        /// <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());
            }
        }
示例#14
0
        /// <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));
        }
示例#15
0
 public RecordKey(RecordType recordType, LedgerPath path, string name)
 {
     this.RecordType = recordType;
     this.Path = path;
     this.Name = name;
 }
示例#16
0
 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;
        }
示例#18
0
        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;
        }
示例#19
0
 /// <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)));
 }
示例#20
0
 /// <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);
            }