@fedify/fedify 0.10.0-dev.199 → 0.10.0-dev.200
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGES.md +20 -1
- package/esm/codegen/schema.yaml +6 -1
- package/esm/runtime/key.js +1 -1
- package/esm/sig/http.js +10 -61
- package/esm/sig/key.js +85 -0
- package/esm/testing/fixtures/example.com/person2 +20 -3
- package/esm/testing/fixtures/server.example/users/alice +20 -0
- package/esm/testing/fixtures/wizard.casa/users/hongminhee +69 -0
- package/esm/vocab/dataintegrityproof.yaml +1 -1
- package/esm/vocab/object.yaml +1 -0
- package/esm/vocab/vocab.js +484 -221
- package/package.json +3 -2
- package/types/codegen/schema.d.ts.map +1 -1
- package/types/sig/http.d.ts +1 -1
- package/types/sig/http.d.ts.map +1 -1
- package/types/sig/key.d.ts +38 -0
- package/types/sig/key.d.ts.map +1 -1
- package/types/sig/proof.d.ts.map +1 -0
- package/types/sig/proof.test.d.ts.map +1 -0
- package/types/testing/keys.d.ts.map +1 -1
- package/types/vocab/vocab.d.ts.map +1 -1
- package/esm/testing/fixtures/example.com/key3 +0 -7
- package/esm/testing/fixtures/example.com/key4 +0 -7
package/CHANGES.md
CHANGED
@@ -74,7 +74,7 @@ To be released.
|
|
74
74
|
[[FEP-8b32], [#54]]
|
75
75
|
|
76
76
|
- Added `proof` property to the `Object` class in the Activity
|
77
|
-
Vocabulary API.
|
77
|
+
Vocabulary API. [[FEP-8b32], [#54]]
|
78
78
|
|
79
79
|
- Added `Object.getProof()` method.
|
80
80
|
- Added `Object.getProofs()` method.
|
@@ -83,6 +83,19 @@ To be released.
|
|
83
83
|
- `Object.clone()` method now accepts `proof` option.
|
84
84
|
- `Object.clone()` method now accepts `proofs` option.
|
85
85
|
|
86
|
+
- Implemented Object Integrity Proofs. [[FEP-8b32], [#54]]
|
87
|
+
|
88
|
+
- Added `signObject()` function.
|
89
|
+
- Added `SignObjectOptions` interface.
|
90
|
+
- Added `createProof()` function.
|
91
|
+
- Added `CreateProofOptions` interface.
|
92
|
+
- Added `verifyObject()` function.
|
93
|
+
- Added `VerifyObjectOptions` interface.
|
94
|
+
- Added `verifyProof()` function.
|
95
|
+
- Added `VerifyProofOptions` interface.
|
96
|
+
- Added `fetchKey()` function.
|
97
|
+
- Added `FetchKeyOptions` interface.
|
98
|
+
|
86
99
|
- Added `context` option to `Object.toJsonLd()` method. This applies to
|
87
100
|
any subclasses of the `Object` class too.
|
88
101
|
|
@@ -97,6 +110,12 @@ To be released.
|
|
97
110
|
`following`, `followers`, `outbox`, `manuallyApprovesFollowers`, and
|
98
111
|
`url`.
|
99
112
|
|
113
|
+
- Added more log messages using the [LogTape] library. Currently the below
|
114
|
+
logger categories are used:
|
115
|
+
|
116
|
+
- `["fedify", "sig", "proof"]`
|
117
|
+
- `["fedify", "sig", "key"]`
|
118
|
+
|
100
119
|
[#54]: https://github.com/dahlia/fedify/issues/54
|
101
120
|
[#55]: https://github.com/dahlia/fedify/issues/55
|
102
121
|
[FEP-521a]: https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md
|
package/esm/codegen/schema.yaml
CHANGED
@@ -28,6 +28,11 @@ $defs:
|
|
28
28
|
Whether to generate singular property accessors. Regardless of
|
29
29
|
this flag, plural property accessors are generated
|
30
30
|
(unless functional is turned on).
|
31
|
+
type: boolean
|
32
|
+
container:
|
33
|
+
description: >-
|
34
|
+
The container type of the property values. It can be unspecified.
|
35
|
+
const: "graph"
|
31
36
|
required:
|
32
37
|
- pluralName
|
33
38
|
- allOf:
|
@@ -167,7 +172,7 @@ properties:
|
|
167
172
|
Marks the type an entity type rather than a value type. Turning on this
|
168
173
|
flag will make property accessors for the type asynchronous, so that they
|
169
174
|
can load the values of the properties from the remote server.
|
170
|
-
|
175
|
+
|
171
176
|
The extended subtypes must have the consistent value of this flag.
|
172
177
|
type: boolean
|
173
178
|
description:
|
package/esm/runtime/key.js
CHANGED
@@ -78,7 +78,7 @@ export async function importMultibaseKey(key) {
|
|
78
78
|
return await dntShim.crypto.subtle.importKey("raw", content, "Ed25519", true, ["verify"]);
|
79
79
|
}
|
80
80
|
else {
|
81
|
-
throw new TypeError("Unsupported key type: " + code);
|
81
|
+
throw new TypeError("Unsupported key type: 0x" + code.toString(16));
|
82
82
|
}
|
83
83
|
}
|
84
84
|
/**
|
package/esm/sig/http.js
CHANGED
@@ -2,10 +2,8 @@ import * as dntShim from "../_dnt.shims.js";
|
|
2
2
|
import { getLogger } from "@logtape/logtape";
|
3
3
|
import { equals } from "../deps/jsr.io/@std/bytes/0.224.0/mod.js";
|
4
4
|
import { decodeBase64, encodeBase64 } from "../deps/jsr.io/@std/encoding/0.224.3/base64.js";
|
5
|
-
import {
|
6
|
-
import {
|
7
|
-
import { CryptographicKey, Object as ASObject } from "../vocab/vocab.js";
|
8
|
-
import { validateCryptoKey } from "./key.js";
|
5
|
+
import { CryptographicKey } from "../vocab/vocab.js";
|
6
|
+
import { fetchKey, validateCryptoKey } from "./key.js";
|
9
7
|
/**
|
10
8
|
* Signs a request using the given private key.
|
11
9
|
* @param request The request to sign.
|
@@ -17,6 +15,9 @@ import { validateCryptoKey } from "./key.js";
|
|
17
15
|
*/
|
18
16
|
export async function signRequest(request, privateKey, keyId) {
|
19
17
|
validateCryptoKey(privateKey, "private");
|
18
|
+
if (privateKey.algorithm.name !== "RSASSA-PKCS1-v1_5") {
|
19
|
+
throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
|
20
|
+
}
|
20
21
|
const url = new URL(request.url);
|
21
22
|
const body = request.method !== "GET" && request.method !== "HEAD"
|
22
23
|
? await request.arrayBuffer()
|
@@ -141,64 +142,12 @@ export async function verifyRequest(request, { documentLoader, contextLoader, ti
|
|
141
142
|
return null;
|
142
143
|
}
|
143
144
|
const { keyId, headers, signature } = sigValues;
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
}
|
150
|
-
catch (_) {
|
151
|
-
logger.debug("Failed to fetch key {keyId}.", { keyId });
|
152
|
-
return null;
|
153
|
-
}
|
154
|
-
let object;
|
155
|
-
try {
|
156
|
-
object = await ASObject.fromJsonLd(document, {
|
157
|
-
documentLoader,
|
158
|
-
contextLoader,
|
159
|
-
});
|
160
|
-
}
|
161
|
-
catch (e) {
|
162
|
-
if (!(e instanceof TypeError))
|
163
|
-
throw e;
|
164
|
-
try {
|
165
|
-
object = await CryptographicKey.fromJsonLd(document, {
|
166
|
-
documentLoader,
|
167
|
-
contextLoader,
|
168
|
-
});
|
169
|
-
}
|
170
|
-
catch (e) {
|
171
|
-
if (e instanceof TypeError) {
|
172
|
-
logger.debug("Failed to verify; key {keyId} returned an invalid object.", { keyId });
|
173
|
-
return null;
|
174
|
-
}
|
175
|
-
throw e;
|
176
|
-
}
|
177
|
-
}
|
178
|
-
let key = null;
|
179
|
-
if (object instanceof CryptographicKey)
|
180
|
-
key = object;
|
181
|
-
else if (isActor(object)) {
|
182
|
-
for await (const k of object.getPublicKeys({ documentLoader, contextLoader })) {
|
183
|
-
if (k.id?.href === keyId) {
|
184
|
-
key = k;
|
185
|
-
break;
|
186
|
-
}
|
187
|
-
}
|
188
|
-
if (key == null) {
|
189
|
-
logger.debug("Failed to verify; object {keyId} returned an {actorType}, " +
|
190
|
-
"but has no key matching {keyId}.", { keyId, actorType: object.constructor.name });
|
191
|
-
return null;
|
192
|
-
}
|
193
|
-
}
|
194
|
-
else {
|
195
|
-
logger.debug("Failed to verify; key {keyId} returned an invalid object.", { keyId });
|
196
|
-
return null;
|
197
|
-
}
|
198
|
-
if (key.publicKey == null) {
|
199
|
-
logger.debug("Failed to verify; key {keyId} has no publicKeyPem field.", { keyId });
|
145
|
+
const key = await fetchKey(new URL(keyId), CryptographicKey, {
|
146
|
+
documentLoader,
|
147
|
+
contextLoader,
|
148
|
+
});
|
149
|
+
if (key == null)
|
200
150
|
return null;
|
201
|
-
}
|
202
151
|
const headerNames = headers.split(/\s+/g);
|
203
152
|
if (!headerNames.includes("(request-target)") || !headerNames.includes("date")) {
|
204
153
|
logger.debug("Failed to verify; required headers missing in the Signature header: " +
|
package/esm/sig/key.js
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
import * as dntShim from "../_dnt.shims.js";
|
2
2
|
import { getLogger } from "@logtape/logtape";
|
3
|
+
import { fetchDocumentLoader, } from "../runtime/docloader.js";
|
4
|
+
import { isActor } from "../vocab/actor.js";
|
5
|
+
import { CryptographicKey, Object } from "../vocab/vocab.js";
|
3
6
|
/**
|
4
7
|
* Checks if the given key is valid and supported. No-op if the key is valid,
|
5
8
|
* otherwise throws an error.
|
@@ -88,3 +91,85 @@ export async function importJwk(jwk, type) {
|
|
88
91
|
validateCryptoKey(key, type);
|
89
92
|
return key;
|
90
93
|
}
|
94
|
+
/**
|
95
|
+
* Fetches a {@link CryptographicKey} or {@link Multikey} from the given URL.
|
96
|
+
* If the given URL contains an {@link Actor} object, it tries to find
|
97
|
+
* the corresponding key in the `publicKey` or `assertionMethod` property.
|
98
|
+
* @typeParam T The type of the key to fetch. Either {@link CryptographicKey}
|
99
|
+
* or {@link Multikey}.
|
100
|
+
* @param keyId The URL of the key.
|
101
|
+
* @param cls The class of the key to fetch. Either {@link CryptographicKey}
|
102
|
+
* or {@link Multikey}.
|
103
|
+
* @param options Options for fetching the key. See {@link FetchKeyOptions}.
|
104
|
+
* @returns The fetched key or `null` if the key is not found.
|
105
|
+
* @since 0.10.0
|
106
|
+
*/
|
107
|
+
export async function fetchKey(keyId,
|
108
|
+
// deno-lint-ignore no-explicit-any
|
109
|
+
cls, { documentLoader, contextLoader } = {}) {
|
110
|
+
const logger = getLogger(["fedify", "sig", "key"]);
|
111
|
+
keyId = typeof keyId === "string" ? keyId : keyId.href;
|
112
|
+
logger.debug("Fetching key {keyId} to verify signature...", { keyId });
|
113
|
+
let document;
|
114
|
+
try {
|
115
|
+
const remoteDocument = await (documentLoader ?? fetchDocumentLoader)(keyId);
|
116
|
+
document = remoteDocument.document;
|
117
|
+
}
|
118
|
+
catch (_) {
|
119
|
+
logger.debug("Failed to fetch key {keyId}.", { keyId });
|
120
|
+
return null;
|
121
|
+
}
|
122
|
+
let object;
|
123
|
+
try {
|
124
|
+
object = await Object.fromJsonLd(document, {
|
125
|
+
documentLoader,
|
126
|
+
contextLoader,
|
127
|
+
});
|
128
|
+
}
|
129
|
+
catch (e) {
|
130
|
+
if (!(e instanceof TypeError))
|
131
|
+
throw e;
|
132
|
+
try {
|
133
|
+
object = await cls.fromJsonLd(document, {
|
134
|
+
documentLoader,
|
135
|
+
contextLoader,
|
136
|
+
});
|
137
|
+
}
|
138
|
+
catch (e) {
|
139
|
+
if (e instanceof TypeError) {
|
140
|
+
logger.debug("Failed to verify; key {keyId} returned an invalid object.", { keyId });
|
141
|
+
return null;
|
142
|
+
}
|
143
|
+
throw e;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
let key = null;
|
147
|
+
if (object instanceof cls)
|
148
|
+
key = object;
|
149
|
+
else if (isActor(object)) {
|
150
|
+
// @ts-ignore: cls is either CryptographicKey or Multikey
|
151
|
+
const keys = cls === CryptographicKey
|
152
|
+
? object.getPublicKeys({ documentLoader, contextLoader })
|
153
|
+
: object.getAssertionMethods({ documentLoader, contextLoader });
|
154
|
+
for await (const k of keys) {
|
155
|
+
if (k.id?.href === keyId) {
|
156
|
+
key = k;
|
157
|
+
break;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
if (key == null) {
|
161
|
+
logger.debug("Failed to verify; object {keyId} returned an {actorType}, " +
|
162
|
+
"but has no key matching {keyId}.", { keyId, actorType: object.constructor.name });
|
163
|
+
return null;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
else {
|
167
|
+
logger.debug("Failed to verify; key {keyId} returned an invalid object.", { keyId });
|
168
|
+
return null;
|
169
|
+
}
|
170
|
+
if (key.publicKey == null) {
|
171
|
+
logger.debug("Failed to verify; key {keyId} has no publicKeyPem field.", { keyId });
|
172
|
+
return null;
|
173
|
+
}
|
174
|
+
return key;
|
175
|
+
}
|
@@ -1,23 +1,40 @@
|
|
1
1
|
{
|
2
2
|
"@context": [
|
3
3
|
"https://www.w3.org/ns/activitystreams",
|
4
|
-
"https://w3id.org/security/v1"
|
4
|
+
"https://w3id.org/security/v1",
|
5
|
+
"https://w3id.org/security/multikey/v1",
|
6
|
+
"https://w3id.org/security/data-integrity/v1",
|
7
|
+
"https://www.w3.org/ns/did/v1"
|
5
8
|
],
|
6
9
|
"id": "https://example.com/person2",
|
7
10
|
"type": "Person",
|
8
11
|
"name": "Jane Doe",
|
9
12
|
"publicKey": [
|
10
13
|
{
|
11
|
-
"id": "https://example.com/key3",
|
14
|
+
"id": "https://example.com/person2#key3",
|
12
15
|
"type": "CryptographicKey",
|
13
16
|
"owner": "https://example.com/person2",
|
14
17
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4GUqWgdiYlN3Su5Gr4l6\ni+xRS8gDDVKZ718vpGk6eIpvqs33q430nRbHIzbHRXRaAhc/1++rUBcK0V4/kjZl\nCSzVtRgGU6HMkmjcD+uE56a8XbTczfltbEDj7afoEuB2F3UhQEWrSz+QJ29DPXaL\nMIa1Yv61NR2vxGqNbdtoMjDORMBYtg77CYbcFkiJHw65PDa7+f/yjLxuCRPye5L7\nhncN0UZuuFoRJmHNRLSg5omBad9WTvQXmSyXEhEdk9fHwlI022AqAzlWbT79hldc\nDSKGGLLbQIs1c3JZIG8G5i6Uh5Vy0Z7tSNBcxbhqoI9i9je4f/x/OPIVc19f04BE\n1LgWuHsftZzRgW9Sdqz53W83XxVdxlyHeywXOnstSWT11f8dkLyQUcHKTH+E6urb\nH+aiPLiRpYK8W7D9KTQA9kZ5JXaEuveBd5vJX7wakhbzAn8pWJU7GYIHNY38Ycok\nmivkU5pY8S2cKFMwY0b7ade3MComlir5P3ZYSjF+n6gRVsT96P+9mNfCu9gXt/f8\nXCyjKlH89kGwuJ7HhR8CuVdm0l+jYozVt6GsDy0hHYyn79NCCAEzP7ZbhBMR0T5V\nrkl+TIGXoJH9WFiz4VxO+NnglF6dNQjDS5IzYLoFRXIK1f3cmQiEB4FZmL70l9HL\nrgwR+Xys83xia79OqFDRezMCAwEAAQ==\n-----END PUBLIC KEY-----\n"
|
15
18
|
},
|
16
19
|
{
|
17
|
-
"id": "https://example.com/key4",
|
20
|
+
"id": "https://example.com/person2#key4",
|
18
21
|
"type": "CryptographicKey",
|
19
22
|
"owner": "https://example.com/person2",
|
20
23
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEALR8epAGDe+cVq5p2Tx49CCfphpk1rNhkNoY9i+XEUfg=\n-----END PUBLIC KEY-----\n"
|
21
24
|
}
|
25
|
+
],
|
26
|
+
"assertionMethod": [
|
27
|
+
{
|
28
|
+
"id": "https://example.com/peson2#key3",
|
29
|
+
"type": "Multikey",
|
30
|
+
"controller": "https://example.com/person2",
|
31
|
+
"publicKeyMultibase": "zgghBUVkqmWS8e1j4aN2yowLAEkJC6wowB9wWmLRACYCok7UzstWcTBp3waKiDUM7wqL9bbBD9W9FvNaXEK2KPCZ9ffhvd5dxChJL9bdPQSrMwa28FEYMGDtcF1uocrYNmZm2dBBMaWrCu8U3s4PpVVhn4hsWDL8GLuE466pkJs9Hy8xmECoaaVgAZLiYDw2gwrjHDiX2i7aDHKfE7aSZWUWmC8nAGNZ7DX5pXoyXK3pxuaCWxNxXwPmaFwgKDyy9uhtBJ8znp9NZXkXHBTQe5uAi8GFwHY5asvqCmYPrAGWxcT6pdbZaJHdWkM7nw6apBHfakKs42oMqdBoJ2WkkresoT1qHrX2GW7gNP9PLtveF4vfEd6cwgHKQCdYgayG3muGfZiPvML75cyfkNrjkctvuQUfMxY9umbd2TG3V3mPnLrvQnqHpuRMZYtCn3nX1qfZaqFhTwT4NFPqVNLqvgR6k9vcuGXn6Ndaumhd5xtTK64jk3e2gPBit9iq6MrFUSoxNsbTty4kqcHAodtkK8CMSxUxbFP1kK3nyy8ZfeMgDCts1KboBcT2m5FMpQpYxKtNBfvhTuyeDDC34uhbY8itmTAnDwSr5mKrniwwDUGPZFejda51TYs1N9D9Ejzaw5Mvr8qN6wahHmsDBWTbWwV6YKVMD1MjAhJBUopWJWB5x6mEBAX25MssKfAEhJyDtqYWjq63uQHUJCsPJp"
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"id": "https://example.com/person2#key4",
|
35
|
+
"type": "Multikey",
|
36
|
+
"controller": "https://example.com/person2",
|
37
|
+
"publicKeyMultibase": "z6MkhVPuyvgG1RkMv67azDqDCDERPXVrUg1i3qchXY5EACE3"
|
38
|
+
}
|
22
39
|
]
|
23
40
|
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
{
|
2
|
+
"@context": [
|
3
|
+
"https://www.w3.org/ns/activitystreams",
|
4
|
+
"https://w3id.org/security/data-integrity/v1",
|
5
|
+
"https://w3id.org/security/multikey/v1",
|
6
|
+
"https://www.w3.org/ns/did/v1"
|
7
|
+
],
|
8
|
+
"type": "Person",
|
9
|
+
"id": "https://server.example/users/alice",
|
10
|
+
"inbox": "https://server.example/users/alice/inbox",
|
11
|
+
"outbox": "https://server.example/users/alice/outbox",
|
12
|
+
"assertionMethod": [
|
13
|
+
{
|
14
|
+
"id": "https://server.example/users/alice#ed25519-key",
|
15
|
+
"type": "Multikey",
|
16
|
+
"controller": "https://server.example/users/alice",
|
17
|
+
"publicKeyMultibase": "z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2"
|
18
|
+
}
|
19
|
+
]
|
20
|
+
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
{
|
2
|
+
"@context": [
|
3
|
+
"https://www.w3.org/ns/activitystreams",
|
4
|
+
"https://www.w3.org/ns/did/v1",
|
5
|
+
"https://w3id.org/security/v1",
|
6
|
+
"https://w3id.org/security/data-integrity/v1",
|
7
|
+
"https://w3id.org/security/multikey/v1",
|
8
|
+
{
|
9
|
+
"MitraJcsEip191Signature2022": "mitra:MitraJcsEip191Signature2022",
|
10
|
+
"PropertyValue": "schema:PropertyValue",
|
11
|
+
"VerifiableIdentityStatement": "mitra:VerifiableIdentityStatement",
|
12
|
+
"featured": "toot:featured",
|
13
|
+
"gateways": "mitra:gateways",
|
14
|
+
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
15
|
+
"mitra": "http://jsonld.mitra.social#",
|
16
|
+
"proofPurpose": "sec:proofPurpose",
|
17
|
+
"proofValue": "sec:proofValue",
|
18
|
+
"schema": "http://schema.org/",
|
19
|
+
"subscribers": "mitra:subscribers",
|
20
|
+
"toot": "http://joinmastodon.org/ns#",
|
21
|
+
"value": "schema:value"
|
22
|
+
}
|
23
|
+
],
|
24
|
+
"assertionMethod": [
|
25
|
+
{
|
26
|
+
"controller": "https://wizard.casa/users/hongminhee",
|
27
|
+
"id": "https://wizard.casa/users/hongminhee#main-key",
|
28
|
+
"publicKeyMultibase": "z4MXj1wBzi9jUstyPzDJGKjQPQWMi9NPMz1xNE4MeJjMpUcPYR7LfniZmXoXhfQ6motM7AAgWw9nHbFmhnNvAfaZMdQgBo2j1ptQNRogJPGzesYi7Yf81T2Kqju3CTCEJje5brBDdhKMpq56h6SwFAtcbPZBykN527ocN2JfvmiqVYNTqPVwoKGuVGKXNx6h87jVGq1kxzj7Q9LBFQnMHbCnMeUJ3KtqJQcPdGwbMw7LWjz4jpHpi6wb7KXBdVnSyKMwB7KyNJFJYqzauPi1UgtTKRzEMNUdCjAFsYff7v93Rr7Yzy4siE4cRVCdMNSQp3KphqczgLNejPKLjMMT9UC7XLitDdd2t3xaEzuamHVBNrFVBFEJ4",
|
29
|
+
"type": "Multikey"
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"controller": "https://wizard.casa/users/hongminhee",
|
33
|
+
"id": "https://wizard.casa/users/hongminhee#ed25519-key",
|
34
|
+
"publicKeyMultibase": "z6MkweqJajqa5jRAJTBVxxu47oCdB7HzmYbBKN8VGbFJmKkC",
|
35
|
+
"type": "Multikey"
|
36
|
+
}
|
37
|
+
],
|
38
|
+
"authentication": [
|
39
|
+
{
|
40
|
+
"controller": "https://wizard.casa/users/hongminhee",
|
41
|
+
"id": "https://wizard.casa/users/hongminhee#main-key",
|
42
|
+
"publicKeyMultibase": "z4MXj1wBzi9jUstyPzDJGKjQPQWMi9NPMz1xNE4MeJjMpUcPYR7LfniZmXoXhfQ6motM7AAgWw9nHbFmhnNvAfaZMdQgBo2j1ptQNRogJPGzesYi7Yf81T2Kqju3CTCEJje5brBDdhKMpq56h6SwFAtcbPZBykN527ocN2JfvmiqVYNTqPVwoKGuVGKXNx6h87jVGq1kxzj7Q9LBFQnMHbCnMeUJ3KtqJQcPdGwbMw7LWjz4jpHpi6wb7KXBdVnSyKMwB7KyNJFJYqzauPi1UgtTKRzEMNUdCjAFsYff7v93Rr7Yzy4siE4cRVCdMNSQp3KphqczgLNejPKLjMMT9UC7XLitDdd2t3xaEzuamHVBNrFVBFEJ4",
|
43
|
+
"type": "Multikey"
|
44
|
+
},
|
45
|
+
{
|
46
|
+
"controller": "https://wizard.casa/users/hongminhee",
|
47
|
+
"id": "https://wizard.casa/users/hongminhee#ed25519-key",
|
48
|
+
"publicKeyMultibase": "z6MkweqJajqa5jRAJTBVxxu47oCdB7HzmYbBKN8VGbFJmKkC",
|
49
|
+
"type": "Multikey"
|
50
|
+
}
|
51
|
+
],
|
52
|
+
"featured": "https://wizard.casa/users/hongminhee/collections/featured",
|
53
|
+
"followers": "https://wizard.casa/users/hongminhee/followers",
|
54
|
+
"following": "https://wizard.casa/users/hongminhee/following",
|
55
|
+
"id": "https://wizard.casa/users/hongminhee",
|
56
|
+
"inbox": "https://wizard.casa/users/hongminhee/inbox",
|
57
|
+
"manuallyApprovesFollowers": true,
|
58
|
+
"name": "洪 民憙 (Hong Minhee)",
|
59
|
+
"outbox": "https://wizard.casa/users/hongminhee/outbox",
|
60
|
+
"preferredUsername": "hongminhee",
|
61
|
+
"publicKey": {
|
62
|
+
"id": "https://wizard.casa/users/hongminhee#main-key",
|
63
|
+
"owner": "https://wizard.casa/users/hongminhee",
|
64
|
+
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUNdOf1fXnMDtcw/elvC\nLlw3TbZUAHSQMCD5su7UzYtHsRsSkErPemkJVUvRGvJnHUEVmb700lyNqcz2l3V0\nj35CAOFK77DY95rr1x7/SSJnOLwCDPA0Vff+RBInwck+8jzGigfkea+Z0/BhmfQE\nqhOSnYOsgQ+jWEJMIQBPA1boDW/636GAgbvfvSPkOPnvwMplCvT/ZUrmzcvGT8by\ntRT4QKrW7zjrYv0VaCHVF9aj+LLyOnCWgUKUHm4oKnq49P8UNen7sCsFRq2NRejK\nf9ymm77inWxrS0mNT4bm9J8/+u2mZjvQaiPiNcLUn4a3fvDnBelD4iKogUKaAQ2F\nzwIDAQAB\n-----END PUBLIC KEY-----\n"
|
65
|
+
},
|
66
|
+
"subscribers": "https://wizard.casa/users/hongminhee/subscribers",
|
67
|
+
"type": "Person",
|
68
|
+
"url": "https://wizard.casa/users/hongminhee"
|
69
|
+
}
|
@@ -50,7 +50,7 @@ properties:
|
|
50
50
|
|
51
51
|
- singularName: created
|
52
52
|
functional: true
|
53
|
-
uri: "
|
53
|
+
uri: "http://purl.org/dc/terms/created"
|
54
54
|
description: The date and time the proof was created.
|
55
55
|
range:
|
56
56
|
- "http://www.w3.org/2001/XMLSchema#dateTime"
|
package/esm/vocab/object.yaml
CHANGED