diff --git a/Cargo.lock b/Cargo.lock index 46324814..80bf0408 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -709,8 +709,8 @@ dependencies = [ "tokio", "tonic", "tracing", - "tracing-appender", - "tracing-subscriber", + "tracing-appender 0.2.1", + "tracing-subscriber 0.2.18", "ttl_cache", "uuid", ] @@ -828,8 +828,8 @@ dependencies = [ "serde_json", "thiserror", "tracing", - "tracing-appender", - "tracing-subscriber", + "tracing-appender 0.1.2", + "tracing-subscriber 0.2.18", ] [[package]] @@ -2724,9 +2724,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ "once_cell", ] @@ -3019,7 +3019,18 @@ checksum = "9965507e507f12c8901432a33e31131222abac31edd90cabbcf85cf544b7127a" dependencies = [ "chrono", "crossbeam-channel", - "tracing-subscriber", + "tracing-subscriber 0.2.18", +] + +[[package]] +name = "tracing-appender" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab026b18a46ac429e5c98bec10ca06424a97b3ad7b3949d9b4a102fff6623c4" +dependencies = [ + "crossbeam-channel", + "time 0.3.5", + "tracing-subscriber 0.3.9", ] [[package]] @@ -3035,11 +3046,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" dependencies = [ "lazy_static", + "valuable", ] [[package]] @@ -3095,6 +3107,17 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -3179,6 +3202,12 @@ dependencies = [ "serde 1.0.124", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.11" diff --git a/Cargo.toml b/Cargo.toml index ffdfab85..06a9dedc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ thiserror = "1.0.24" tokio = { version = "1.9.0", features = [ "full" ] } tonic = "0.5.2" tracing = "0.1" -tracing-appender = "0.1" +tracing-appender = "0.2" tracing-subscriber = "0.2" ttl_cache = "0.5.1" uuid = { version = "0.8.2", features = [ "serde" ] } diff --git a/examples/js/client.ts b/examples/js/client.ts index b3cbeead..d07537d6 100644 --- a/examples/js/client.ts +++ b/examples/js/client.ts @@ -88,6 +88,8 @@ class Client { } async balanceUpdate(transactionAdmin, user_id, asset, business, business_id, delta, detail) { + let meta = transactionAdmin === null ? {} : await this.auth.getAuthTokenMeta(transactionAdmin); + return await this.client.BalanceUpdate( { user_id, @@ -97,7 +99,7 @@ class Client { delta, detail: JSON.stringify(detail), }, - await this.auth.getAuthTokenMeta(transactionAdmin) + meta ); } roundOrderInput(market, amount, price) { diff --git a/examples/js/tests/authorization.ts b/examples/js/tests/authorization.ts index 8a2e2363..0bd951db 100644 --- a/examples/js/tests/authorization.ts +++ b/examples/js/tests/authorization.ts @@ -1,5 +1,5 @@ import { fee, market, ORDER_SIDE_BID, ORDER_TYPE_LIMIT, TestUser } from "../config"; // dotenv -import { defaultClient as client, defaultClient as grpcClient } from "../client"; +import { defaultClient as grpcClient } from "../client"; import { defaultRESTClient as restClient } from "../RESTClient"; import * as assert from "assert"; import { Authentication } from "../authentication"; @@ -7,6 +7,8 @@ import { depositAssets } from "../exchange_helper"; const GRPC_PERMISSION_DENIED_CODE = 7; const GRPC_PERMISSION_DENIED_TEXT = "Requires admin role."; +const GRPC_DEPOSIT_PERMISSION_DENIED_TEXT = "Requires deposit-admin role."; +const GRPC_WITHDRAWAL_PERMISSION_DENIED_TEXT = "Requires withdrawal-admin role."; const GRPC_TOKEN_NOT_FOUND_CODE = 16; const GRPC_TOKEN_NOT_FOUND_TEXT = "Token not found"; const GRPC_INVALID_TOKEN_CODE = 16; @@ -105,16 +107,7 @@ async function grpcRejectUserWithoutToken() { } try { - // surpress logging - let console_log = console.log; - console.log = function () { - /* do nothing */ - }; - await depositAssets({ USDT: "100.0", ETH: "50.0" }, process.env.KC_USER1_ID, NON_EXISTANT_USER); - - // reactivate logging - console.log = console_log; throw Error("GRPC call must fail as no authentication token is provided!"); } catch (e) { grpcAssertErrorNoTokenProvided(e); @@ -180,24 +173,95 @@ async function grpcPermitAccessToRegularUser() { await grpcClient.balanceQueryWithValidToken(); await grpcClient.orderCancelAll(TestUser.USER1, market); - // surpress logging - let console_log = console.log; - console.log = function () { - /* do nothing */ - }; - // === SETTING UP MARKET DATA THAT IS LATER BEING USED FOR orderDetail TESTS. === // await depositAssets({ USDT: "100.0", ETH: "50.0" }, process.env.KC_USER1_ID, TestUser.DEPOSIT_ADMIN); await grpcClient.orderPut(TestUser.USER1, market, ORDER_SIDE_BID, ORDER_TYPE_LIMIT, "10", "1.1", fee, fee); await batchOrderPut(TestUser.USER1); - // reactivate logging - console.log = console_log; - await grpcClient.orderCancel(TestUser.USER1, market, 2); await grpcClient.orderQuery(TestUser.USER1, market); } +async function grpcTestDepositAccess() { + // Deposit should begranted to the deposit admin user. + await depositAssets({ USDT: "100.0", ETH: "50.0" }, process.env.KC_USER1_ID, TestUser.DEPOSIT_ADMIN); + + try { + await depositAssets({ USDT: "100.0", ETH: "50.0" }, process.env.KC_USER1_ID, TestUser.ADMIN); + throw Error("Admin must not be able to deposit funds"); + } catch (e) { + grpcAssertErrorDepositPermissionDenied(e); + } + + try { + await depositAssets({ USDT: "100.0", ETH: "50.0" }, process.env.KC_USER1_ID, TestUser.WITHDRAWAL_ADMIN); + throw Error("Withdrawal Admin must not be able to deposit funds"); + } catch (e) { + grpcAssertErrorDepositPermissionDenied(e); + } + + try { + await depositAssets({ USDT: "100.0", ETH: "50.0" }, process.env.KC_USER1_ID, TestUser.USER1); + throw Error("Regular user must not be able to deposit funds"); + } catch (e) { + grpcAssertErrorDepositPermissionDenied(e); + } + + try { + await depositAssets({ USDT: "100.0", ETH: "50.0" }, process.env.KC_USER1_ID, TestUser.USER1); + throw Error("Regular user must not be able to deposit funds"); + } catch (e) { + grpcAssertErrorDepositPermissionDenied(e); + } + + try { + await depositAssets({ USDT: "100.0", ETH: "50.0" }, process.env.KC_USER1_ID, null); + throw Error("Anonymous must not be able to deposit funds"); + } catch (e) { + grpcAssertErrorNoTokenProvided(e); + } +} + +async function grpcTestWithdrawalAccess() { + // Deposit should begranted to the withdrawal admin user. + await depositAssets({ USDT: "-100.0", ETH: "-50.0" }, process.env.KC_USER1_ID, TestUser.WITHDRAWAL_ADMIN); + + try { + await depositAssets({ USDT: "-100.0", ETH: "-50.0" }, process.env.KC_USER1_ID, TestUser.ADMIN); + throw Error("Admin must not be able to withdraw funds"); + } catch (e) { + grpcAssertErrorWithdrawalPermissionDenied(e); + } + + try { + await depositAssets({ USDT: "-100.0", ETH: "-50.0" }, process.env.KC_USER1_ID, TestUser.DEPOSIT_ADMIN); + throw Error("Deposit Admin must not be able to withdraw funds"); + } catch (e) { + grpcAssertErrorWithdrawalPermissionDenied(e); + } + + try { + await depositAssets({ USDT: "-100.0", ETH: "-50.0" }, process.env.KC_USER1_ID, TestUser.USER1); + throw Error("Regular user must not be able to withdraw funds"); + } catch (e) { + grpcAssertErrorWithdrawalPermissionDenied(e); + } + + try { + await depositAssets({ USDT: "-100.0", ETH: "-50.0" }, process.env.KC_USER1_ID, TestUser.USER1); + throw Error("Regular user must not be able to withdraw funds"); + } catch (e) { + grpcAssertErrorWithdrawalPermissionDenied(e); + } + + try { + await depositAssets({ USDT: "-100.0", ETH: "-50.0" }, process.env.KC_USER1_ID, null); + throw Error("Anonymous must not be able to withdraw funds"); + } catch (e) { + grpcAssertErrorNoTokenProvided(e); + } +} + async function grpcTestPublicEndpoints() { // should work without authentication ... await grpcClient.assetList({}); @@ -391,6 +455,16 @@ function grpcAssertErrorPermissionDenied(error) { assert.equal(error.details, GRPC_PERMISSION_DENIED_TEXT); } +function grpcAssertErrorDepositPermissionDenied(error) { + assert.equal(error.code, GRPC_PERMISSION_DENIED_CODE); + assert.equal(error.details, GRPC_DEPOSIT_PERMISSION_DENIED_TEXT); +} + +function grpcAssertErrorWithdrawalPermissionDenied(error) { + assert.equal(error.code, GRPC_PERMISSION_DENIED_CODE); + assert.equal(error.details, GRPC_WITHDRAWAL_PERMISSION_DENIED_TEXT); +} + function grpcAssertErrorNoTokenProvided(error) { assert.equal(error.code, GRPC_TOKEN_NOT_FOUND_CODE); assert.equal(error.details, GRPC_TOKEN_NOT_FOUND_TEXT); @@ -417,10 +491,14 @@ function restAssertAuthenticationNotSatisfactory(error) { } async function main() { + // disable logging + // eslint-disable-next-line @typescript-eslint/no-empty-function + console.log = () => {}; + let auth = new Authentication(); try { - console.log("GRPC authentication"); + console.info("GRPC authentication"); await grpcPermitAdminAccess(); await grpcRejectUserAccessingAdminCalls(); await grpcRejectAnonymousAccessingAdminCalls(); @@ -429,8 +507,10 @@ async function main() { await grpcRejectUserWithInvalidSignatureToken(); await grpcRejectUserWithExpiredToken(); await grpcPermitAccessToRegularUser(); + await grpcTestDepositAccess(); + await grpcTestWithdrawalAccess(); await grpcTestPublicEndpoints(); - console.log("REST authentication"); + console.info("REST authentication"); await restRejectUserWithoutToken(); await restRejectUserWithInvalidToken(); await restRejectUserWithInvalidToken2(); @@ -441,7 +521,7 @@ async function main() { await restTestRegularEndpoints(auth); await testAdminEndpoints(auth); - console.log("Authorization tests successful!"); + console.info("Authorization tests successful!"); } catch (error) { console.error("Caught error:", error); process.exit(1);