@structured-id/ui-core 4.14.0 → 4.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
|
|
87
87
|
<script setup lang="ts">
|
|
88
88
|
import { reactive, computed, watch } from "vue";
|
|
89
|
-
import type { Profile } from "
|
|
89
|
+
import type { Profile } from "../composables/useIdentityApi";
|
|
90
90
|
|
|
91
91
|
const props = withDefaults(
|
|
92
92
|
defineProps<{
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
</div>
|
|
53
53
|
|
|
54
54
|
<q-list v-else-if="credentials.length > 0" separator>
|
|
55
|
-
<q-item v-for="cred in credentials" :key="cred.id">
|
|
55
|
+
<q-item v-for="cred in credentials" :key="cred.id.toString()">
|
|
56
56
|
<q-item-section avatar>
|
|
57
57
|
<q-icon :name="credIcon(cred.type)" :color="credColor(cred.type)" />
|
|
58
58
|
</q-item-section>
|
|
@@ -96,11 +96,9 @@
|
|
|
96
96
|
</template>
|
|
97
97
|
|
|
98
98
|
<script setup lang="ts">
|
|
99
|
-
import {
|
|
100
|
-
type Credential,
|
|
101
|
-
CredentialType,
|
|
102
|
-
} from "@structured-id/proto/sid/v1/identity/identity";
|
|
99
|
+
import { CredentialType } from "@structured-id/proto/sid/v1/identity/identity";
|
|
103
100
|
import { Timestamp } from "@structured-id/proto/google/protobuf/timestamp";
|
|
101
|
+
import type { Credential } from "../composables/useIdentityApi";
|
|
104
102
|
import type { FactorCategory } from "../composables/useSecurityLevel";
|
|
105
103
|
|
|
106
104
|
defineProps<{
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { ref } from "vue";
|
|
2
|
+
import { ref, shallowRef } from "vue";
|
|
3
|
+
import { CredentialId, PrincipalId } from "@structured-id/ids";
|
|
4
|
+
import type {
|
|
5
|
+
Credential as IdentityCredential,
|
|
6
|
+
Principal as IdentityPrincipal,
|
|
7
|
+
} from "./useIdentityApi";
|
|
3
8
|
import {
|
|
4
9
|
useSecurityLevel,
|
|
5
10
|
SecurityLevel,
|
|
@@ -42,7 +47,6 @@ function makeCred(
|
|
|
42
47
|
|
|
43
48
|
function makePrincipal(type: PrincipalType, verified: boolean): Principal {
|
|
44
49
|
return {
|
|
45
|
-
id: "p-1",
|
|
46
50
|
type,
|
|
47
51
|
value: "test",
|
|
48
52
|
verified,
|
|
@@ -54,6 +58,30 @@ function makePrincipal(type: PrincipalType, verified: boolean): Principal {
|
|
|
54
58
|
// ── Security Level ──
|
|
55
59
|
|
|
56
60
|
describe("useSecurityLevel", () => {
|
|
61
|
+
// Regression: the assessment took the wire types, so the typed lists the
|
|
62
|
+
// identity composable answers (held in shallow refs) did not fit it.
|
|
63
|
+
it("assesses the identity composable's typed lists", () => {
|
|
64
|
+
const creds = shallowRef<IdentityCredential[]>([
|
|
65
|
+
{
|
|
66
|
+
...makeCred(CredentialType.OPAQUE),
|
|
67
|
+
id: CredentialId.parse("0192f3a4-7c1e-7b2a-9d4e-3f5a6b7c8d50"),
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
70
|
+
const principals = shallowRef<IdentityPrincipal[]>([
|
|
71
|
+
{
|
|
72
|
+
...makePrincipal(PrincipalType.EMAIL, true),
|
|
73
|
+
id: PrincipalId.parse("0192f3a4-7c1e-7b2a-9d4e-3f5a6b7c8d51"),
|
|
74
|
+
sourceEmailId: undefined,
|
|
75
|
+
},
|
|
76
|
+
]);
|
|
77
|
+
const { factorCount, recoveryMethods } = useSecurityLevel(
|
|
78
|
+
creds,
|
|
79
|
+
principals,
|
|
80
|
+
);
|
|
81
|
+
expect(factorCount.value).toBe(1);
|
|
82
|
+
expect(recoveryMethods.value).toContain("recovery_email");
|
|
83
|
+
});
|
|
84
|
+
|
|
57
85
|
it("MINIMAL with no credentials", () => {
|
|
58
86
|
const { securityLevel } = useSecurityLevel(ref([]), ref([]));
|
|
59
87
|
expect(securityLevel.value).toBe(SecurityLevel.MINIMAL);
|
|
@@ -13,6 +13,15 @@ import {
|
|
|
13
13
|
PrincipalType,
|
|
14
14
|
} from "@structured-id/proto/sid/v1/identity/identity";
|
|
15
15
|
|
|
16
|
+
/** What the assessment reads of a credential: its kind and authenticator. */
|
|
17
|
+
export type CredentialFacts = Pick<Credential, "type" | "info">;
|
|
18
|
+
|
|
19
|
+
/** What the assessment reads of a login handle: its kind and proof. */
|
|
20
|
+
export type PrincipalFacts = Pick<
|
|
21
|
+
Principal,
|
|
22
|
+
"type" | "verified" | "needsAddressConfirmation"
|
|
23
|
+
>;
|
|
24
|
+
|
|
16
25
|
// ── Security Level ──
|
|
17
26
|
|
|
18
27
|
export enum SecurityLevel {
|
|
@@ -66,7 +75,7 @@ const RECOVERABILITY_COLORS: Record<RecoverabilityLevel, string> = {
|
|
|
66
75
|
|
|
67
76
|
export type FactorCategory = "knowledge" | "possession" | "inherence";
|
|
68
77
|
|
|
69
|
-
function getCategory(cred:
|
|
78
|
+
function getCategory(cred: CredentialFacts): FactorCategory | null {
|
|
70
79
|
switch (cred.type) {
|
|
71
80
|
case CredentialType.OPAQUE:
|
|
72
81
|
case CredentialType.LEGACY_HASH:
|
|
@@ -89,7 +98,7 @@ function getCategory(cred: Credential): FactorCategory | null {
|
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
|
|
92
|
-
function isHardwareKey(cred:
|
|
101
|
+
function isHardwareKey(cred: CredentialFacts): boolean {
|
|
93
102
|
return (
|
|
94
103
|
cred.type === CredentialType.WEBAUTHN &&
|
|
95
104
|
cred.info.oneofKind === "webauthnInfo" &&
|
|
@@ -113,8 +122,8 @@ export interface ActionNudge {
|
|
|
113
122
|
// ── Composable ──
|
|
114
123
|
|
|
115
124
|
export function useSecurityLevel(
|
|
116
|
-
credentials: Ref<
|
|
117
|
-
identifiers: Ref<
|
|
125
|
+
credentials: Readonly<Ref<readonly CredentialFacts[]>>,
|
|
126
|
+
identifiers: Readonly<Ref<readonly PrincipalFacts[]>>,
|
|
118
127
|
) {
|
|
119
128
|
const authFactors = computed(() =>
|
|
120
129
|
credentials.value.filter((c) => c.type !== CredentialType.RECOVERY),
|