-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature manifest and permission system #766
Changes from 1 commit
9e101ab
0ab7368
f548702
143297b
dfed28b
5ce76cc
6b26077
8781770
a1c6f72
5b1aaec
34aa3ba
ed75324
f7f36e8
2058fd0
deb3707
6d1d627
44f5ce0
1f8b316
0137897
7736247
3a5b0ba
453675c
55fd385
cd306e8
2b40a8d
6b36687
c402d0b
f33b0e8
ce0aa85
89051bf
93d6ae8
768df1f
0729674
7842694
524a745
548acf0
16d1ff5
c09a795
47b3efc
1cb3650
2b9c5dc
c18cd5b
31feebc
3f0772b
ecb338f
f94021b
1d4e281
6bc60f1
8d38246
93cd013
4dacb2c
5400351
cc4a340
dab02a5
38fc8d7
26ff492
d00903e
12a1576
162758e
2cdb847
84c38f9
fcdab61
7c7a82d
efac87f
a3a1b0d
b44ec29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
ContractPermission
correctly
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
using Neo.IO; | ||
using Neo.IO.Json; | ||
using System; | ||
using System.IO; | ||
using System.Linq; | ||
|
||
|
@@ -45,7 +44,7 @@ public class ContractManifest : ISerializable | |
/// <summary> | ||
/// The permissions field is an array containing a set of Permission objects. It describes which contracts may be invoked and which methods are called. | ||
/// </summary> | ||
public WildCardContainer<ContractPermission> Permissions { get; set; } | ||
public ContractPermission[] Permissions { get; set; } | ||
|
||
/// <summary> | ||
/// The trusts field is an array containing a set of contract hashes or group public keys. It can also be assigned with a wildcard *. If it is a wildcard *, then it means that it trusts any contract. | ||
|
@@ -68,7 +67,7 @@ public static ContractManifest CreateDefault(UInt160 hash) | |
{ | ||
return new ContractManifest() | ||
{ | ||
Permissions = WildCardContainer<ContractPermission>.CreateWildcard(), | ||
Permissions = new[] { ContractPermission.DefaultPermission }, | ||
Abi = new ContractAbi() | ||
{ | ||
Hash = hash, | ||
|
@@ -91,20 +90,7 @@ public static ContractManifest CreateDefault(UInt160 hash) | |
/// <returns>Return true or false</returns> | ||
public bool CanCall(ContractManifest manifest, string method) | ||
{ | ||
if (Groups.Any(a => manifest.Groups.Any(b => a.PubKey.Equals(b.PubKey)))) | ||
{ | ||
// Same group | ||
return true; | ||
} | ||
|
||
if (manifest.Trusts != null && !manifest.Trusts.IsWildcard && !manifest.Trusts.Contains(Hash)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. |
||
{ | ||
// null == * wildcard | ||
// You don't have rights in the contract | ||
return false; | ||
} | ||
|
||
return Permissions == null || Permissions.IsWildcard || Permissions.Any(u => u.IsAllowed(manifest.Hash, method)); | ||
return Permissions.Any(u => u.IsAllowed(manifest, method)); | ||
} | ||
|
||
/// <summary> | ||
|
@@ -139,7 +125,7 @@ public JObject ToJson() | |
json["groups"] = new JArray(Groups.Select(u => u.ToJson()).ToArray()); | ||
json["features"] = feature; | ||
json["abi"] = Abi.ToJson(); | ||
json["permissions"] = Permissions.ToJson(); | ||
json["permissions"] = Permissions.Select(p => p.ToJson()).ToArray(); | ||
json["trusts"] = Trusts.ToJson(); | ||
json["safeMethods"] = SafeMethods.ToJson(); | ||
|
||
|
@@ -173,7 +159,7 @@ private void DeserializeFromJson(JObject json) | |
Abi = ContractAbi.FromJson(json["abi"]); | ||
Groups = ((JArray)json["groups"]).Select(u => ContractGroup.FromJson(u)).ToArray(); | ||
Features = ContractFeatures.NoProperty; | ||
Permissions = WildCardContainer<ContractPermission>.FromJson(json["permissions"], ContractPermission.FromJson); | ||
Permissions = ((JArray)json["permissions"]).Select(u => ContractPermission.FromJson(u)).ToArray(); | ||
Trusts = WildCardContainer<UInt160>.FromJson(json["trusts"], u => UInt160.Parse(u.AsString())); | ||
SafeMethods = WildCardContainer<string>.FromJson(json["safeMethods"], u => u.AsString()); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,20 +7,26 @@ namespace Neo.SmartContract.Manifest | |
/// <summary> | ||
/// The permissions field is an array containing a set of Permission objects. It describes which contracts may be invoked and which methods are called. | ||
/// </summary> | ||
public class ContractPermission : IJsonSerializable | ||
public class ContractPermission | ||
{ | ||
/// <summary> | ||
/// The contract field indicates the contract to be invoked. It can be a hash of a contract, a public key of a group, or a wildcard *. | ||
/// If it specifies a hash of a contract, then the contract will be invoked; If it specifies a public key of a group, then any contract in this group will be invoked; If it specifies a wildcard*, then any contract will be invoked. | ||
/// </summary> | ||
public UInt160 Contract { get; set; } | ||
public ContractPermissionDescriptor Contract { get; set; } | ||
|
||
/// <summary> | ||
/// The methods field is an array containing a set of methods to be called. It can also be assigned with a wildcard *. If it is a wildcard *, then it means that any method can be called. | ||
/// If a contract invokes a contract or method that is not declared in the manifest at runtime, the invocation will fail. | ||
/// </summary> | ||
public WildCardContainer<string> Methods { get; set; } | ||
|
||
public static readonly ContractPermission DefaultPermission = new ContractPermission | ||
{ | ||
Contract = ContractPermissionDescriptor.CreateWildcard(), | ||
Methods = WildCardContainer<string>.CreateWildcard() | ||
}; | ||
|
||
/// <summary> | ||
/// Parse ContractPermission from json | ||
/// </summary> | ||
|
@@ -30,7 +36,7 @@ public static ContractPermission FromJson(JObject json) | |
{ | ||
return new ContractPermission | ||
{ | ||
Contract = UInt160.Parse(json["contract"].AsString()), | ||
Contract = ContractPermissionDescriptor.FromJson(json["contract"]), | ||
Methods = WildCardContainer<string>.FromJson(json["methods"], u => u.AsString()), | ||
}; | ||
} | ||
|
@@ -41,26 +47,28 @@ public static ContractPermission FromJson(JObject json) | |
public JObject ToJson() | ||
{ | ||
var json = new JObject(); | ||
json["contract"] = Contract.ToString(); | ||
json["contract"] = Contract.ToJson(); | ||
json["methods"] = Methods.ToJson(); | ||
return json; | ||
} | ||
|
||
/// <summary> | ||
/// Return true if is allowed | ||
/// </summary> | ||
/// <param name="contractHash">Contract hash</param> | ||
/// <param name="manifest">The manifest of which contract we are calling</param> | ||
/// <param name="method">Method</param> | ||
/// <returns>Return true or false</returns> | ||
public bool IsAllowed(UInt160 contractHash, string method) | ||
public bool IsAllowed(ContractManifest manifest, string method) | ||
{ | ||
if (!Contract.Equals(contractHash)) | ||
if (Contract.IsHash) | ||
{ | ||
// 0x00 = * wildcard | ||
if (Contract != UInt160.Zero) return false; | ||
if (!Contract.Hash.Equals(manifest.Hash)) return false; | ||
} | ||
|
||
return Methods == null || Methods.IsWildcard || Methods.Contains(method); | ||
else if (Contract.IsGroup) | ||
{ | ||
if (manifest.Groups.All(p => !p.PubKey.Equals(Contract.Group))) return false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does All work as expected or Sum would also work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What sum? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is checking, for all groups, if any of them is not equal. Maybe this is strange, because one of yours groups may not allow you to enter, but another one can allow you to interact with the desired contract. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
} | ||
return Methods.IsWildcard || Methods.Contains(method); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using Neo.Cryptography.ECC; | ||
using Neo.IO.Json; | ||
using System; | ||
|
||
namespace Neo.SmartContract.Manifest | ||
{ | ||
public class ContractPermissionDescriptor | ||
{ | ||
public UInt160 Hash { get; } | ||
public ECPoint Group { get; } | ||
|
||
public bool IsHash => Hash != null; | ||
public bool IsGroup => Group != null; | ||
public bool IsWildcard => Hash is null && Group is null; | ||
|
||
private ContractPermissionDescriptor(UInt160 hash, ECPoint group) | ||
{ | ||
this.Hash = hash; | ||
this.Group = group; | ||
} | ||
|
||
public static ContractPermissionDescriptor Create(UInt160 hash) | ||
{ | ||
return new ContractPermissionDescriptor(hash, null); | ||
} | ||
|
||
public static ContractPermissionDescriptor Create(ECPoint group) | ||
{ | ||
return new ContractPermissionDescriptor(null, group); | ||
} | ||
|
||
public static ContractPermissionDescriptor CreateWildcard() | ||
{ | ||
return new ContractPermissionDescriptor(null, null); | ||
} | ||
|
||
public static ContractPermissionDescriptor FromJson(JObject json) | ||
{ | ||
string str = json.AsString(); | ||
if (str.Length == 42) | ||
return Create(UInt160.Parse(str)); | ||
if (str.Length == 66) | ||
return Create(ECPoint.Parse(str, ECCurve.Secp256r1)); | ||
if (str == "*") | ||
return CreateWildcard(); | ||
throw new FormatException(); | ||
} | ||
|
||
public JObject ToJson() | ||
{ | ||
if (IsHash) return Hash.ToString(); | ||
if (IsGroup) return Group.ToString(); | ||
return "*"; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does these groups really work? A contract can be part of more than one group in this current design, right?
And why the signature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without signature, you can join any group, which is not by design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I got it, in the current design, how is able to sign for entering? Is it a multisig with 1 single threshold?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just put the signature in the json.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The group identifier is the PublicKey, right?
03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c
Which signatures will be allowed?
If we have 10 members of the group, should we create a MultiSig 1/10? For each new member, append an additional PubKey?
Sorry for the trivial questions, @erikzhang, trying to get the idea here...aehauheau
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the specification here: #287