Skip to content

Commit

Permalink
Query Tokens for password protection (#362)
Browse files Browse the repository at this point in the history
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
Magnus-Kuhn and mergify[bot] authored Dec 13, 2024
1 parent f56c40d commit 59d5579
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 6 deletions.
27 changes: 27 additions & 0 deletions packages/runtime/src/useCases/common/Schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23071,6 +23071,33 @@ export const GetTokensRequest: any = {
}
}
]
},
"passwordProtection": {
"type": "string",
"enum": [
"",
"!"
]
},
"passwordProtection.password": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"passwordProtection.passwordIsPin": {
"type": "string",
"enum": [
"true",
"!"
]
}
},
"additionalProperties": false
Expand Down
28 changes: 25 additions & 3 deletions packages/runtime/src/useCases/transport/tokens/GetTokens.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { QueryTranslator } from "@js-soft/docdb-querytranslator";
import { Result } from "@js-soft/ts-utils";
import { CachedToken, Token, TokenController } from "@nmshd/transport";
import { CachedToken, PasswordProtection, Token, TokenController } from "@nmshd/transport";
import { Inject } from "@nmshd/typescript-ioc";
import { nameof } from "ts-simple-nameof";
import { TokenDTO } from "../../../types";
Expand All @@ -13,6 +13,9 @@ export interface GetTokensQuery {
createdByDevice?: string | string[];
expiresAt?: string | string[];
forIdentity?: string | string[];
passwordProtection?: "" | "!";
"passwordProtection.password"?: string | string[];
"passwordProtection.passwordIsPin"?: "true" | "!";
}

export interface GetTokensRequest {
Expand All @@ -33,14 +36,33 @@ export class GetTokensUseCase extends UseCase<GetTokensRequest, TokenDTO[]> {
[nameof<TokenDTO>((t) => t.createdBy)]: true,
[nameof<TokenDTO>((t) => t.createdByDevice)]: true,
[nameof<TokenDTO>((t) => t.expiresAt)]: true,
[nameof<TokenDTO>((t) => t.forIdentity)]: true
[nameof<TokenDTO>((t) => t.forIdentity)]: true,
[nameof<TokenDTO>((r) => r.passwordProtection)]: true,
[`${nameof<TokenDTO>((r) => r.passwordProtection)}.password`]: true,
[`${nameof<TokenDTO>((r) => r.passwordProtection)}.passwordIsPin`]: true
},
alias: {
[nameof<TokenDTO>((t) => t.createdAt)]: `${nameof<Token>((t) => t.cache)}.${[nameof<CachedToken>((t) => t.createdAt)]}`,
[nameof<TokenDTO>((t) => t.createdBy)]: `${nameof<Token>((t) => t.cache)}.${[nameof<CachedToken>((t) => t.createdBy)]}`,
[nameof<TokenDTO>((t) => t.createdByDevice)]: `${nameof<Token>((t) => t.cache)}.${[nameof<CachedToken>((t) => t.createdByDevice)]}`,
[nameof<TokenDTO>((t) => t.expiresAt)]: `${nameof<Token>((t) => t.cache)}.${[nameof<CachedToken>((t) => t.expiresAt)]}`,
[nameof<TokenDTO>((t) => t.forIdentity)]: `${nameof<Token>((t) => t.cache)}.${[nameof<CachedToken>((t) => t.forIdentity)]}`
[nameof<TokenDTO>((t) => t.forIdentity)]: `${nameof<Token>((t) => t.cache)}.${[nameof<CachedToken>((t) => t.forIdentity)]}`,
[nameof<TokenDTO>((r) => r.passwordProtection)]: nameof<Token>((r) => r.passwordProtection)
},
custom: {
[`${nameof<TokenDTO>((r) => r.passwordProtection)}.password`]: (query: any, input: string) => {
query[`${nameof<Token>((t) => t.passwordProtection)}.${nameof<PasswordProtection>((t) => t.password)}`] = input;
},
[`${nameof<TokenDTO>((t) => t.passwordProtection)}.passwordIsPin`]: (query: any, input: string) => {
if (input === "true") {
query[`${nameof<Token>((t) => t.passwordProtection)}.${nameof<PasswordProtection>((t) => t.passwordType)}`] = {
$regex: "^pin"
};
}
if (input === "!") {
query[`${nameof<Token>((t) => t.passwordProtection)}.${nameof<PasswordProtection>((t) => t.passwordType)}`] = "pw";
}
}
}
});

Expand Down
57 changes: 54 additions & 3 deletions packages/runtime/test/transport/tokens.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,69 @@ describe("Tokens errors", () => {

describe("Tokens query", () => {
test("query own tokens", async () => {
const token = await uploadOwnToken(runtimeServices1.transport, runtimeServices1.address);
const token = await uploadOwnToken(runtimeServices1.transport, runtimeServices1.address, { password: "password" });
const conditions = new QueryParamConditions<GetTokensQuery>(token, runtimeServices1.transport)
.addDateSet("expiresAt")
.addDateSet("createdAt")
.addStringSet("createdByDevice")
.addStringSet("forIdentity");
.addStringSet("forIdentity")
.addSingleCondition({
expectedResult: true,
key: "passwordProtection",
value: ""
})
.addSingleCondition({
expectedResult: false,
key: "passwordProtection",
value: "!"
})
.addStringSet("passwordProtection.password")
.addSingleCondition({
expectedResult: false,
key: "passwordProtection.passwordIsPin",
value: "true"
})
.addSingleCondition({
expectedResult: true,
key: "passwordProtection.passwordIsPin",
value: "!"
});
await conditions.executeTests((c, q) => c.tokens.getTokens({ query: q, ownerRestriction: OwnerRestriction.Own }));
});

test("query own PIN-protected tokens", async () => {
const token = await uploadOwnToken(runtimeServices1.transport, runtimeServices1.address, { password: "1234", passwordIsPin: true });
const conditions = new QueryParamConditions<GetTokensQuery>(token, runtimeServices1.transport)
.addStringSet("passwordProtection.password")
.addSingleCondition({
expectedResult: true,
key: "passwordProtection.passwordIsPin",
value: "true"
})
.addSingleCondition({
expectedResult: false,
key: "passwordProtection.passwordIsPin",
value: "!"
});
await conditions.executeTests((c, q) => c.tokens.getTokens({ query: q, ownerRestriction: OwnerRestriction.Own }));
});

test("query peer tokens", async () => {
const token = await exchangeToken(runtimeServices1.transport, runtimeServices2.transport);
const conditions = new QueryParamConditions<GetTokensQuery>(token, runtimeServices2.transport).addDateSet("expiresAt").addDateSet("createdAt").addStringSet("createdBy");
const conditions = new QueryParamConditions<GetTokensQuery>(token, runtimeServices2.transport)
.addDateSet("expiresAt")
.addDateSet("createdAt")
.addStringSet("createdBy")
.addSingleCondition({
expectedResult: false,
key: "passwordProtection",
value: ""
})
.addSingleCondition({
expectedResult: true,
key: "passwordProtection",
value: "!"
});
await conditions.executeTests((c, q) => c.tokens.getTokens({ query: q, ownerRestriction: OwnerRestriction.Peer }));
});
});
Expand Down

0 comments on commit 59d5579

Please sign in to comment.