Skip to content

Commit

Permalink
feat: implement ic_oss_cluster with access control; improve cwt API
Browse files Browse the repository at this point in the history
  • Loading branch information
zensh committed Jul 11, 2024
1 parent 1d146bf commit 7034772
Show file tree
Hide file tree
Showing 21 changed files with 568 additions and 121 deletions.
23 changes: 13 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@ jobs:
rustup target add wasm32-unknown-unknown
cargo install ic-wasm
mkdir out
cargo build --target wasm32-unknown-unknown --release --locked -p ic_oss_bucket
CAN="ic_oss_bucket"
cp "target/wasm32-unknown-unknown/release/$CAN.wasm" out/
cp "src/$CAN/$CAN.did" "out/$CAN.did"
ic-wasm "out/$CAN.wasm" -o "out/$CAN.wasm" metadata candid:service -f "out/$CAN.did" -v public
ic-wasm "out/$CAN.wasm" -o "out/$CAN.wasm" shrink
ic-wasm "out/$CAN.wasm" -o "out/$CAN.wasm" optimize O3 --inline-functions-with-loops
gzip "out/$CAN.wasm"
SHA256="$(sha256sum < "out/$CAN.wasm.gz" | sed 's/ .*$//g')"
echo $SHA256 > "out/$CAN.wasm.gz.$SHA256.txt"
cargo build --target wasm32-unknown-unknown --release --locked -p ic_oss_bucket -p ic_oss_cluster
for CAN in ic_oss_bucket ic_oss_cluster
do
cp "target/wasm32-unknown-unknown/release/$CAN.wasm" out/
cp "src/$CAN/$CAN.did" "out/$CAN.did"
WASM="out/$CAN.wasm"
ic-wasm $WASM -o $WASM metadata candid:service -f "out/$CAN.did" -v public
ic-wasm $WASM -o $WASM shrink
ic-wasm $WASM -o $WASM optimize O3 --inline-functions-with-loops
gzip $WASM
SHA256="$(sha256sum < "out/$CAN.wasm.gz" | sed 's/ .*$//g')"
echo $SHA256 > "out/$CAN.wasm.gz.$SHA256.txt"
done
ls -lah out
- name: Release
uses: softprops/action-gh-release@v2
Expand Down
76 changes: 49 additions & 27 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ hmac = "0.12"
sha2 = "0.10"
sha3 = "0.10"
num-traits = "0.2"
ic-cdk = "0.14"
ic-cdk = "0.15"
ic-cdk-timers = "0.8"
ic-stable-structures = "0.6"
icrc-ledger-types = "0.1"
Expand All @@ -56,3 +56,4 @@ anyhow = "1"
crc32fast = "1.4"
url = "2.5"
once_cell = "1.19"
getrandom = { version = "0.2", features = ["custom"] }
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ test:
# cargo install ic-wasm
build-wasm:
@cargo build --release --target wasm32-unknown-unknown --package ic_oss_bucket
@cargo build --release --target wasm32-unknown-unknown --package ic_oss_cluster

# cargo install candid-extractor
build-did:
candid-extractor target/wasm32-unknown-unknown/release/ic_oss_bucket.wasm > src/ic_oss_bucket/ic_oss_bucket.did
candid-extractor target/wasm32-unknown-unknown/release/ic_oss_cluster.wasm > src/ic_oss_cluster/ic_oss_cluster.did
2 changes: 1 addition & 1 deletion src/ic_oss/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ futures-util = { workspace = true }
crc32fast = { workspace = true }
sha3 = { workspace = true }
ic-oss-types = { path = "../ic_oss_types", version = "0.5" }
ic-agent = "0.35"
ic-agent = "0.36"
1 change: 1 addition & 0 deletions src/ic_oss_bucket/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ ic-cdk-timers = { workspace = true }
ic-stable-structures = { workspace = true }
ic-http-certification = { workspace = true }
icrc-ledger-types = { workspace = true }
getrandom = { workspace = true }
ic-oss-types = { path = "../ic_oss_types", version = "0.5" }
hyperx = { git = "https://github.com/ldclabs/hyperx", version = "1.4" }
lazy_static = "1.4"
8 changes: 4 additions & 4 deletions src/ic_oss_bucket/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ic-oss-cli -i debug/uploader.pem identity

dfx canister call ic_oss_bucket admin_set_managers "(vec {principal \"$MYID\"; principal \"nprym-ylvyz-ig3fr-lgcmn-zzzt4-tyuix-3v6bm-fsel7-6lq6x-zh2w7-zqe\"})"

dfx canister call ic_oss_bucket admin_update_bucket "(record {
dfx canister call ic_oss_bucket admin_update_bucket '(record {
name = null;
max_file_size = null;
max_folder_depth = null;
Expand All @@ -39,11 +39,11 @@ dfx canister call ic_oss_bucket admin_update_bucket "(record {
enable_hash_index = null;
status = null;
visibility = null;
trusted_ecdsa_pub_keys = null;
trusted_ecdsa_pub_keys = opt vec {blob "\02\bd\ef\d5\d8\91\7a\81\cc\91\60\ba\19\95\69\d4\47\d9\d4\7e\e6\71\6c\b8\dc\18\aa\d2\be\8c\4c\cd\eb"};
trusted_eddsa_pub_keys = opt vec {vec {19; 152; 246; 44; 109; 26; 69; 124; 81; 186; 106; 75; 95; 61; 189; 47; 105; 252; 169; 50; 22; 33; 141; 200; 153; 126; 65; 107; 209; 125; 147; 202}};
}, null)"
}, null)'

dfx canister call ic_oss_bucket list_files '(2, null, null, opt vec{132; 67; 161; 1; 39; 160; 88; 142; 166; 2; 120; 63; 122; 55; 119; 106; 112; 45; 118; 54; 102; 101; 51; 45; 107; 107; 115; 117; 53; 45; 50; 54; 102; 54; 52; 45; 100; 101; 100; 116; 119; 45; 106; 55; 110; 100; 106; 45; 53; 55; 111; 110; 120; 45; 113; 103; 97; 54; 99; 45; 101; 116; 53; 101; 51; 45; 110; 106; 120; 53; 51; 45; 116; 97; 101; 3; 120; 27; 109; 109; 114; 120; 117; 45; 102; 113; 97; 97; 97; 45; 97; 97; 97; 97; 112; 45; 97; 104; 104; 110; 97; 45; 99; 97; 105; 4; 26; 102; 143; 124; 240; 5; 26; 102; 143; 110; 224; 6; 26; 102; 143; 110; 224; 9; 120; 24; 70; 111; 108; 100; 101; 114; 46; 42; 58; 49; 32; 66; 117; 99; 107; 101; 116; 46; 82; 101; 97; 100; 46; 42; 88; 64; 210; 38; 140; 40; 73; 180; 152; 145; 49; 12; 114; 27; 202; 202; 177; 163; 235; 140; 234; 54; 118; 79; 125; 78; 80; 204; 34; 220; 129; 8; 77; 2; 199; 210; 196; 189; 235; 130; 159; 138; 88; 162; 111; 191; 48; 61; 174; 99; 187; 110; 150; 149; 191; 43; 253; 25; 38; 53; 226; 80; 52; 158; 193; 7})'
dfx canister call ic_oss_bucket list_files '(2, null, null, opt blob "\84\44\a1\01\38\2e\a0\58\ac\a7\01\78\1b\61\6a\75\71\34\2d\72\75\61\61\61\2d\61\61\61\61\61\2d\71\61\61\67\61\2d\63\61\69\02\78\3f\7a\37\77\6a\70\2d\76\36\66\65\33\2d\6b\6b\73\75\35\2d\32\36\66\36\34\2d\64\65\64\74\77\2d\6a\37\6e\64\6a\2d\35\37\6f\6e\78\2d\71\67\61\36\63\2d\65\74\35\65\33\2d\6e\6a\78\35\33\2d\74\61\65\03\78\1b\6d\6d\72\78\75\2d\66\71\61\61\61\2d\61\61\61\61\70\2d\61\68\68\6e\61\2d\63\61\69\04\1a\66\8f\ce\68\05\1a\66\8f\c0\58\06\1a\66\8f\c0\58\09\78\18\46\6f\6c\64\65\72\2e\2a\3a\31\20\42\75\63\6b\65\74\2e\52\65\61\64\2e\2a\58\40\52\66\3e\e7\55\7e\99\2c\66\6d\65\56\54\9f\30\a1\2e\aa\56\69\66\b6\c6\e9\75\d7\c9\02\4c\24\1d\5d\7e\83\7d\c1\13\c6\00\91\56\d9\6a\ae\34\c3\a5\c9\b4\99\b3\47\b7\68\54\8d\dd\9c\9a\9b\a0\f9\1a\f5")'
dfx canister call ic_oss_bucket list_folders '(0, null)'

ic-oss-cli -i debug/uploader.pem upload -b mmrxu-fqaaa-aaaap-ahhna-cai --file README.md
Expand Down
17 changes: 17 additions & 0 deletions src/ic_oss_bucket/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,21 @@ fn is_controller() -> Result<(), String> {
}
}

#[cfg(all(
target_arch = "wasm32",
target_vendor = "unknown",
target_os = "unknown"
))]
/// A getrandom implementation that always fails
pub fn always_fail(_buf: &mut [u8]) -> Result<(), getrandom::Error> {
Err(getrandom::Error::UNSUPPORTED)
}

#[cfg(all(
target_arch = "wasm32",
target_vendor = "unknown",
target_os = "unknown"
))]
getrandom::register_custom_getrandom!(always_fail);

ic_cdk::export_candid!();
10 changes: 6 additions & 4 deletions src/ic_oss_bucket/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,16 @@ impl Bucket {
}

if let Some(token) = sign1_token {
let token = Token::from_ed25519_sign1(
let token = Token::from_sign1(
&token,
&self.trusted_ecdsa_pub_keys,
&self.trusted_eddsa_pub_keys,
BUCKET_TOKEN_AAD,
now_sec as i64,
)
.map_err(|err| (401, err))?;
if &token.subject == caller && &token.audience == canister {
return Ok(token.scope);
return Policies::try_from(token.scope.as_str()).map_err(|err| (403u16, err));
}
}

Expand All @@ -106,15 +107,16 @@ impl Bucket {
}

if let Some(token) = sign1_token {
let token = Token::from_ed25519_sign1(
let token = Token::from_sign1(
&token,
&self.trusted_ecdsa_pub_keys,
&self.trusted_eddsa_pub_keys,
BUCKET_TOKEN_AAD,
now_sec as i64,
)
.map_err(|err| (401, err))?;
if &token.subject == caller && &token.audience == canister {
return Ok(token.scope);
return Policies::try_from(token.scope.as_str()).map_err(|err| (403u16, err));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/ic_oss_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ crc32fast = { workspace = true }
sha3 = { workspace = true }
ic-oss = { path = "../ic_oss", version = "0.5" }
ic-oss-types = { path = "../ic_oss_types", version = "0.5" }
ic-agent = "0.35"
ic-agent = "0.36"
anyhow = "1"
clap = { version = "=4.5", features = ["derive"] }
infer = "0.15"
Expand Down
14 changes: 11 additions & 3 deletions src/ic_oss_cluster/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ license.workspace = true
crate-type = ["cdylib"]

[dependencies]
bytes = { workspace = true }
candid = { workspace = true }
ciborium = { workspace = true }
sha2 = { workspace = true }
sha3 = { workspace = true }
ic-cdk = { workspace = true }
ic-cdk-timers = { workspace = true }
ic-stable-structures = { workspace = true }
base64 = { workspace = true }
ciborium = { workspace = true }
hex = { workspace = true }
coset = { workspace = true }
serde = { workspace = true }
serde_bytes = { workspace = true }
getrandom = { workspace = true }
ic-oss-types = { path = "../ic_oss_types", version = "0.5" }
20 changes: 18 additions & 2 deletions src/ic_oss_cluster/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,25 @@ A cluster canister of [ic-oss](https://github.com/ldclabs/ic-oss).

## Running locally

Deploy the cluster canister:
Deploy to local network:
```bash
dfx deploy ic_oss_cluster
dfx deploy ic_oss_cluster --argument "(opt variant {Init =
record {
ecdsa_key_name = \"dfx_test_key\";
}
})"

dfx canister call ic_oss_cluster get_state '(null)'

MYID=$(dfx identity get-principal)

dfx canister call ic_oss_cluster admin_set_managers "(vec {principal \"$MYID\"})"

dfx canister call ic_oss_cluster admin_sign_access_token '(record {
subject = principal "z7wjp-v6fe3-kksu5-26f64-dedtw-j7ndj-57onx-qga6c-et5e3-njx53-tae";
audience = principal "mmrxu-fqaaa-aaaap-ahhna-cai";
scope = "Folder.*:1 Bucket.Read.*";
})'
```

## License
Expand Down
19 changes: 18 additions & 1 deletion src/ic_oss_cluster/ic_oss_cluster.did
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
service : { sha3_256 : () -> (text) query; sha_256 : () -> (text) query }
type ChainArgs = variant { Upgrade : record {}; Init : InitArgs };
type InitArgs = record { ecdsa_key_name : text; token_expiration : nat64 };
type Result = variant { Ok; Err : text };
type Result_1 = variant { Ok : blob; Err : text };
type Result_2 = variant { Ok : State; Err };
type State = record {
ecdsa_token_public_key : text;
ecdsa_key_name : text;
managers : vec principal;
token_expiration : nat64;
};
type Token = record { subject : principal; audience : principal; scope : text };
service : (opt ChainArgs) -> {
admin_set_managers : (vec principal) -> (Result);
admin_sign_access_token : (Token) -> (Result_1);
get_state : (opt blob) -> (Result_2) query;
validate_admin_set_managers : (vec principal) -> (Result) query;
}
Loading

0 comments on commit 7034772

Please sign in to comment.