@twin.org/web 0.0.1-next.6 → 0.0.1-next.60
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/dist/cjs/index.cjs +274 -98
- package/dist/esm/index.mjs +275 -100
- package/dist/types/index.d.ts +3 -1
- package/dist/types/models/IJwk.d.ts +2 -58
- package/dist/types/models/IJwtHeader.d.ts +2 -18
- package/dist/types/models/IJwtPayload.d.ts +2 -33
- package/dist/types/models/headerTypes.d.ts +8 -8
- package/dist/types/models/jwkCryptoKey.d.ts +4 -0
- package/dist/types/models/mimeTypes.d.ts +4 -0
- package/dist/types/utils/fetchHelper.d.ts +7 -0
- package/dist/types/utils/jwk.d.ts +35 -0
- package/dist/types/utils/jws.d.ts +22 -0
- package/dist/types/utils/jwt.d.ts +67 -29
- package/docs/changelog.md +166 -1
- package/docs/reference/classes/FetchError.md +16 -8
- package/docs/reference/classes/FetchHelper.md +104 -28
- package/docs/reference/classes/Jwk.md +107 -0
- package/docs/reference/classes/Jws.md +81 -0
- package/docs/reference/classes/Jwt.md +261 -105
- package/docs/reference/classes/MimeTypeHelper.md +9 -5
- package/docs/reference/index.md +3 -2
- package/docs/reference/interfaces/IHttpHeaders.md +1 -1
- package/docs/reference/interfaces/IJwk.md +2 -106
- package/docs/reference/interfaces/IJwtHeader.md +5 -23
- package/docs/reference/interfaces/IJwtPayload.md +5 -55
- package/docs/reference/type-aliases/HeaderTypes.md +1 -1
- package/docs/reference/type-aliases/HttpMethod.md +1 -1
- package/docs/reference/type-aliases/HttpStatusCode.md +1 -1
- package/docs/reference/type-aliases/JwkCryptoKey.md +5 -0
- package/docs/reference/type-aliases/MimeTypes.md +1 -1
- package/docs/reference/variables/HeaderTypes.md +8 -8
- package/docs/reference/variables/MimeTypes.md +6 -0
- package/locales/en.json +11 -1
- package/package.json +7 -6
- package/dist/types/models/jwtAlgorithms.d.ts +0 -17
- package/docs/reference/type-aliases/JwtAlgorithms.md +0 -5
- package/docs/reference/variables/JwtAlgorithms.md +0 -19
package/dist/cjs/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@twin.org/core');
|
|
4
4
|
var crypto = require('@twin.org/crypto');
|
|
5
|
+
var jose = require('jose');
|
|
5
6
|
|
|
6
7
|
// Copyright 2024 IOTA Stiftung.
|
|
7
8
|
// SPDX-License-Identifier: Apache-2.0.
|
|
@@ -39,35 +40,35 @@ const HeaderTypes = {
|
|
|
39
40
|
/**
|
|
40
41
|
* Content Type.
|
|
41
42
|
*/
|
|
42
|
-
ContentType: "
|
|
43
|
+
ContentType: "content-type",
|
|
43
44
|
/**
|
|
44
45
|
* Content Length.
|
|
45
46
|
*/
|
|
46
|
-
ContentLength: "
|
|
47
|
+
ContentLength: "content-length",
|
|
47
48
|
/**
|
|
48
49
|
* Content Disposition.
|
|
49
50
|
*/
|
|
50
|
-
ContentDisposition: "
|
|
51
|
+
ContentDisposition: "content-disposition",
|
|
51
52
|
/**
|
|
52
53
|
* Accept.
|
|
53
54
|
*/
|
|
54
|
-
Accept: "
|
|
55
|
+
Accept: "accept",
|
|
55
56
|
/**
|
|
56
57
|
* Authorization.
|
|
57
58
|
*/
|
|
58
|
-
Authorization: "
|
|
59
|
+
Authorization: "authorization",
|
|
59
60
|
/**
|
|
60
61
|
* Cookie.
|
|
61
62
|
*/
|
|
62
|
-
Cookie: "
|
|
63
|
+
Cookie: "cookie",
|
|
63
64
|
/**
|
|
64
65
|
* Set Cookie.
|
|
65
66
|
*/
|
|
66
|
-
SetCookie: "
|
|
67
|
+
SetCookie: "set-cookie",
|
|
67
68
|
/**
|
|
68
69
|
* Location
|
|
69
70
|
*/
|
|
70
|
-
Location: "
|
|
71
|
+
Location: "location"
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
// Copyright 2024 IOTA Stiftung.
|
|
@@ -345,23 +346,6 @@ const HttpStatusCode = {
|
|
|
345
346
|
networkAuthenticationRequired: 511
|
|
346
347
|
};
|
|
347
348
|
|
|
348
|
-
// Copyright 2024 IOTA Stiftung.
|
|
349
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
350
|
-
/**
|
|
351
|
-
* The cryptographic algorithms supported for JSON Web Tokens and JSON Web Keys.
|
|
352
|
-
*/
|
|
353
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
354
|
-
const JwtAlgorithms = {
|
|
355
|
-
/**
|
|
356
|
-
* HMAC using SHA-256.
|
|
357
|
-
*/
|
|
358
|
-
HS256: "HS256",
|
|
359
|
-
/**
|
|
360
|
-
* EdDSA using Ed25519.
|
|
361
|
-
*/
|
|
362
|
-
EdDSA: "EdDSA"
|
|
363
|
-
};
|
|
364
|
-
|
|
365
349
|
// Copyright 2024 IOTA Stiftung.
|
|
366
350
|
// SPDX-License-Identifier: Apache-2.0.
|
|
367
351
|
/**
|
|
@@ -389,6 +373,10 @@ const MimeTypes = {
|
|
|
389
373
|
* JSON-LD - application/ld+json
|
|
390
374
|
*/
|
|
391
375
|
JsonLd: "application/ld+json",
|
|
376
|
+
/**
|
|
377
|
+
* JWT - application/jwt
|
|
378
|
+
*/
|
|
379
|
+
Jwt: "application/jwt",
|
|
392
380
|
/**
|
|
393
381
|
* XML - application/xml
|
|
394
382
|
*/
|
|
@@ -555,7 +543,7 @@ class FetchHelper {
|
|
|
555
543
|
if (isErr && core.Is.stringValue(err.message) && err.message.includes("Failed to fetch")) {
|
|
556
544
|
lastError = new FetchError(source, `${FetchHelper._CLASS_NAME_CAMEL_CASE}.connectivity`, HttpStatusCode.serviceUnavailable, {
|
|
557
545
|
url
|
|
558
|
-
});
|
|
546
|
+
}, err);
|
|
559
547
|
}
|
|
560
548
|
else {
|
|
561
549
|
const isAbort = isErr && err.name === "AbortError";
|
|
@@ -570,7 +558,7 @@ class FetchHelper {
|
|
|
570
558
|
if (isErr && "statusText" in err) {
|
|
571
559
|
props.statusText = err.statusText;
|
|
572
560
|
}
|
|
573
|
-
lastError = new FetchError(source, `${FetchHelper._CLASS_NAME_CAMEL_CASE}.${isAbort ? "timeout" : "general"}`, httpStatus, props);
|
|
561
|
+
lastError = new FetchError(source, `${FetchHelper._CLASS_NAME_CAMEL_CASE}.${isAbort ? "timeout" : "general"}`, httpStatus, props, err);
|
|
574
562
|
}
|
|
575
563
|
}
|
|
576
564
|
finally {
|
|
@@ -698,6 +686,15 @@ class FetchHelper {
|
|
|
698
686
|
static async getCacheEntry(url) {
|
|
699
687
|
return core.AsyncCache.get(`${FetchHelper._CACHE_PREFIX}${url}`);
|
|
700
688
|
}
|
|
689
|
+
/**
|
|
690
|
+
* Set a cache entry.
|
|
691
|
+
* @param url The url for the request.
|
|
692
|
+
* @param value The value to cache.
|
|
693
|
+
* @returns The cache entry if it exists.
|
|
694
|
+
*/
|
|
695
|
+
static async setCacheEntry(url, value) {
|
|
696
|
+
core.AsyncCache.set(`${FetchHelper._CACHE_PREFIX}${url}`, value);
|
|
697
|
+
}
|
|
701
698
|
/**
|
|
702
699
|
* Remove a cache entry.
|
|
703
700
|
* @param url The url for the request.
|
|
@@ -710,7 +707,146 @@ class FetchHelper {
|
|
|
710
707
|
// Copyright 2024 IOTA Stiftung.
|
|
711
708
|
// SPDX-License-Identifier: Apache-2.0.
|
|
712
709
|
/**
|
|
713
|
-
* Class to
|
|
710
|
+
* Class to handle JSON Web Keys.
|
|
711
|
+
*/
|
|
712
|
+
class Jwk {
|
|
713
|
+
/**
|
|
714
|
+
* Runtime name for the class.
|
|
715
|
+
* @internal
|
|
716
|
+
*/
|
|
717
|
+
static _CLASS_NAME = "Jwk";
|
|
718
|
+
/**
|
|
719
|
+
* Convert the JWK to a crypto key.
|
|
720
|
+
* @param jwk The JWK to convert.
|
|
721
|
+
* @param alg The alg to be used, defaults to jwk.alg.
|
|
722
|
+
* @returns The crypto key.
|
|
723
|
+
*/
|
|
724
|
+
static async toCryptoKey(jwk, alg) {
|
|
725
|
+
core.Guards.object(Jwk._CLASS_NAME, "jwk", jwk);
|
|
726
|
+
try {
|
|
727
|
+
return jose.importJWK(jwk, alg);
|
|
728
|
+
}
|
|
729
|
+
catch (err) {
|
|
730
|
+
throw new core.GeneralError(Jwk._CLASS_NAME, "jwkImportFailed", undefined, err);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Convert the Ed25519 private key to a crypto key.
|
|
735
|
+
* @param privateKey The private key to use.
|
|
736
|
+
* @returns The crypto key.
|
|
737
|
+
*/
|
|
738
|
+
static async fromEd25519Private(privateKey) {
|
|
739
|
+
core.Guards.uint8Array(Jwk._CLASS_NAME, "privateKey", privateKey);
|
|
740
|
+
const publicKey = crypto.Ed25519.publicKeyFromPrivateKey(privateKey);
|
|
741
|
+
const jwk = {
|
|
742
|
+
kty: "OKP",
|
|
743
|
+
use: "enc",
|
|
744
|
+
alg: "EdDSA",
|
|
745
|
+
crv: "Ed25519",
|
|
746
|
+
x: core.Converter.bytesToBase64Url(publicKey),
|
|
747
|
+
d: core.Converter.bytesToBase64Url(privateKey)
|
|
748
|
+
};
|
|
749
|
+
return jwk;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Convert the Ed25519 public key to a crypto key.
|
|
753
|
+
* @param publicKey The private key to use.
|
|
754
|
+
* @returns The crypto key.
|
|
755
|
+
*/
|
|
756
|
+
static async fromEd25519Public(publicKey) {
|
|
757
|
+
core.Guards.uint8Array(Jwk._CLASS_NAME, "publicKey", publicKey);
|
|
758
|
+
const jwk = {
|
|
759
|
+
kty: "OKP",
|
|
760
|
+
use: "sig",
|
|
761
|
+
alg: "EdDSA",
|
|
762
|
+
crv: "Ed25519",
|
|
763
|
+
x: core.Converter.bytesToBase64Url(publicKey)
|
|
764
|
+
};
|
|
765
|
+
return jwk;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Convert the JWK to raw keys.
|
|
769
|
+
* @param jwk The JWK to convert to raw.
|
|
770
|
+
* @returns The crypto key.
|
|
771
|
+
*/
|
|
772
|
+
static async toRaw(jwk) {
|
|
773
|
+
core.Guards.object(Jwk._CLASS_NAME, "jwk", jwk);
|
|
774
|
+
let publicKey;
|
|
775
|
+
let privateKey;
|
|
776
|
+
if (core.Is.stringBase64Url(jwk.x)) {
|
|
777
|
+
publicKey = core.Converter.base64UrlToBytes(jwk.x);
|
|
778
|
+
}
|
|
779
|
+
if (core.Is.stringBase64Url(jwk.d)) {
|
|
780
|
+
privateKey = core.Converter.base64UrlToBytes(jwk.d);
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
publicKey,
|
|
784
|
+
privateKey
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// Copyright 2024 IOTA Stiftung.
|
|
790
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
791
|
+
/**
|
|
792
|
+
* Class to handle JSON Web Signatures.
|
|
793
|
+
*/
|
|
794
|
+
class Jws {
|
|
795
|
+
/**
|
|
796
|
+
* Runtime name for the class.
|
|
797
|
+
* @internal
|
|
798
|
+
*/
|
|
799
|
+
static _CLASS_NAME = "Jws";
|
|
800
|
+
/**
|
|
801
|
+
* Create a signature.
|
|
802
|
+
* @param privateKey The private key to use.
|
|
803
|
+
* @param hash The hash to sign.
|
|
804
|
+
* @param algOverride An optional algorithm override.
|
|
805
|
+
* @returns The signature.
|
|
806
|
+
*/
|
|
807
|
+
static async create(privateKey, hash, algOverride) {
|
|
808
|
+
core.Guards.defined(Jws._CLASS_NAME, "privateKey", privateKey);
|
|
809
|
+
core.Guards.uint8Array(Jws._CLASS_NAME, "hash", hash);
|
|
810
|
+
try {
|
|
811
|
+
const jws = await new jose.CompactSign(hash)
|
|
812
|
+
.setProtectedHeader({
|
|
813
|
+
alg: algOverride ?? (core.Is.uint8Array(privateKey) ? "EdDSA" : privateKey.algorithm.name),
|
|
814
|
+
b64: false,
|
|
815
|
+
crit: ["b64"]
|
|
816
|
+
})
|
|
817
|
+
.sign(privateKey);
|
|
818
|
+
return jws;
|
|
819
|
+
}
|
|
820
|
+
catch (err) {
|
|
821
|
+
throw new core.GeneralError(Jws._CLASS_NAME, "createFailed", undefined, err);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Verify a signature.
|
|
826
|
+
* @param jws The signature to verify.
|
|
827
|
+
* @param publicKey The public key to verify the signature with.
|
|
828
|
+
* @param hash The hash to verify.
|
|
829
|
+
* @returns True if the signature was verified.
|
|
830
|
+
*/
|
|
831
|
+
static async verify(jws, publicKey, hash) {
|
|
832
|
+
core.Guards.stringValue(Jws._CLASS_NAME, "jws", jws);
|
|
833
|
+
core.Guards.defined(Jws._CLASS_NAME, "publicKey", publicKey);
|
|
834
|
+
core.Guards.uint8Array(Jws._CLASS_NAME, "hash", hash);
|
|
835
|
+
try {
|
|
836
|
+
const jwsParts = jws.split(".");
|
|
837
|
+
await jose.flattenedVerify({ protected: jwsParts[0], payload: hash, signature: jwsParts[2] }, publicKey);
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
840
|
+
catch (err) {
|
|
841
|
+
throw new core.GeneralError(Jws._CLASS_NAME, "verifyFailed", undefined, err);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// Copyright 2024 IOTA Stiftung.
|
|
847
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
848
|
+
/**
|
|
849
|
+
* Class to handle JSON Web Tokens.
|
|
714
850
|
*/
|
|
715
851
|
class Jwt {
|
|
716
852
|
/**
|
|
@@ -727,9 +863,8 @@ class Jwt {
|
|
|
727
863
|
*/
|
|
728
864
|
static async encode(header, payload, key) {
|
|
729
865
|
core.Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
730
|
-
core.Guards.arrayOneOf(Jwt._CLASS_NAME, "header.alg", header.alg, Object.values(JwtAlgorithms));
|
|
731
866
|
core.Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
732
|
-
core.Guards.
|
|
867
|
+
core.Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
733
868
|
return Jwt.internalEncode(header, payload, key);
|
|
734
869
|
}
|
|
735
870
|
/**
|
|
@@ -741,7 +876,7 @@ class Jwt {
|
|
|
741
876
|
*/
|
|
742
877
|
static async encodeWithSigner(header, payload, signer) {
|
|
743
878
|
core.Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
744
|
-
core.Guards.
|
|
879
|
+
core.Guards.stringValue(Jwt._CLASS_NAME, "header.alg", header.alg);
|
|
745
880
|
core.Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
746
881
|
core.Guards.function(Jwt._CLASS_NAME, "signer", signer);
|
|
747
882
|
return Jwt.internalEncode(header, payload, undefined, signer);
|
|
@@ -788,13 +923,8 @@ class Jwt {
|
|
|
788
923
|
*/
|
|
789
924
|
static async verify(token, key) {
|
|
790
925
|
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
791
|
-
core.Guards.
|
|
792
|
-
|
|
793
|
-
const verified = await Jwt.verifySignature(decoded.header, decoded.payload, decoded.signature, key);
|
|
794
|
-
return {
|
|
795
|
-
verified,
|
|
796
|
-
...decoded
|
|
797
|
-
};
|
|
926
|
+
core.Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
927
|
+
return Jwt.verifySignature(token, key);
|
|
798
928
|
}
|
|
799
929
|
/**
|
|
800
930
|
* Verify a token.
|
|
@@ -805,79 +935,131 @@ class Jwt {
|
|
|
805
935
|
static async verifyWithVerifier(token, verifier) {
|
|
806
936
|
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
807
937
|
core.Guards.function(Jwt._CLASS_NAME, "verifier", verifier);
|
|
808
|
-
|
|
809
|
-
const decoded = await Jwt.decode(token);
|
|
810
|
-
const verified = await Jwt.verifySignature(decoded.header, decoded.payload, decoded.signature, undefined, verifier);
|
|
811
|
-
return {
|
|
812
|
-
verified,
|
|
813
|
-
...decoded
|
|
814
|
-
};
|
|
938
|
+
return Jwt.verifySignature(token, undefined, verifier);
|
|
815
939
|
}
|
|
816
940
|
/**
|
|
817
941
|
* Verify a token by parts.
|
|
818
|
-
* @param
|
|
819
|
-
* @param payload The payload to verify.
|
|
820
|
-
* @param signature The signature to verify.
|
|
942
|
+
* @param token The token to verify.
|
|
821
943
|
* @param key The key for verifying the token, if not provided no verification occurs.
|
|
822
944
|
* @param verifier Custom verification method.
|
|
823
945
|
* @returns True if the parts are verified.
|
|
824
946
|
*/
|
|
825
|
-
static async verifySignature(
|
|
947
|
+
static async verifySignature(token, key, verifier) {
|
|
948
|
+
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
826
949
|
const hasKey = core.Is.notEmpty(key);
|
|
827
950
|
const hasVerifier = core.Is.notEmpty(verifier);
|
|
828
951
|
if (!hasKey && !hasVerifier) {
|
|
829
952
|
throw new core.GeneralError(Jwt._CLASS_NAME, "noKeyOrVerifier");
|
|
830
953
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
core.Is.object(payload) &&
|
|
834
|
-
core.Is.uint8Array(signature) &&
|
|
835
|
-
core.Is.arrayOneOf(header.alg, Object.values(JwtAlgorithms))) {
|
|
836
|
-
const segments = [];
|
|
837
|
-
const headerBytes = core.Converter.utf8ToBytes(JSON.stringify(header));
|
|
838
|
-
segments.push(core.Converter.bytesToBase64Url(headerBytes));
|
|
839
|
-
const payloadBytes = core.Converter.utf8ToBytes(JSON.stringify(payload));
|
|
840
|
-
segments.push(core.Converter.bytesToBase64Url(payloadBytes));
|
|
841
|
-
const jwtHeaderAndPayload = core.Converter.utf8ToBytes(segments.join("."));
|
|
842
|
-
verifier ??= async (alg, k, p, s) => Jwt.defaultVerifier(alg, k, p, s);
|
|
843
|
-
verified = await verifier(header.alg, key, jwtHeaderAndPayload, signature);
|
|
844
|
-
}
|
|
845
|
-
return verified;
|
|
954
|
+
verifier ??= async (t, k) => Jwt.defaultVerifier(t, k);
|
|
955
|
+
return verifier(token, key);
|
|
846
956
|
}
|
|
847
957
|
/**
|
|
848
958
|
* The default signer for the JWT.
|
|
849
|
-
* @param
|
|
850
|
-
* @param key The key to sign with.
|
|
959
|
+
* @param header The header to sign.
|
|
851
960
|
* @param payload The payload to sign.
|
|
961
|
+
* @param key The optional key to sign with.
|
|
852
962
|
* @returns The signature.
|
|
853
963
|
*/
|
|
854
|
-
static async defaultSigner(
|
|
855
|
-
core.Guards.
|
|
856
|
-
core.Guards.
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
964
|
+
static async defaultSigner(header, payload, key) {
|
|
965
|
+
core.Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
966
|
+
core.Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
967
|
+
core.Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
968
|
+
const signer = new jose.SignJWT(payload);
|
|
969
|
+
signer.setProtectedHeader(header);
|
|
970
|
+
let finalKey = key;
|
|
971
|
+
if (header.alg === "EdDSA" && core.Is.uint8Array(key)) {
|
|
972
|
+
// Jose does not support Ed25519 keys in raw format, so we need to convert it to PKCS8.
|
|
973
|
+
finalKey = await crypto.Ed25519.privateKeyToPkcs8(key);
|
|
860
974
|
}
|
|
861
|
-
return
|
|
975
|
+
return signer.sign(finalKey);
|
|
862
976
|
}
|
|
863
977
|
/**
|
|
864
978
|
* The default verifier for the JWT.
|
|
865
|
-
* @param
|
|
979
|
+
* @param token The token to verify.
|
|
866
980
|
* @param key The key to verify with.
|
|
867
|
-
* @
|
|
868
|
-
|
|
869
|
-
|
|
981
|
+
* @returns The header and payload if verification successful.
|
|
982
|
+
*/
|
|
983
|
+
static async defaultVerifier(token, key) {
|
|
984
|
+
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
985
|
+
core.Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
986
|
+
try {
|
|
987
|
+
const result = await jose.jwtVerify(token, key);
|
|
988
|
+
return {
|
|
989
|
+
header: result.protectedHeader,
|
|
990
|
+
payload: result.payload
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
catch (err) {
|
|
994
|
+
throw new core.GeneralError(Jwt._CLASS_NAME, "verifyFailed", undefined, err);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Create bytes for signing from header and payload.
|
|
999
|
+
* @param header The header.
|
|
1000
|
+
* @param payload The payload.
|
|
1001
|
+
* @returns The bytes to sign.
|
|
870
1002
|
*/
|
|
871
|
-
static
|
|
872
|
-
core.Guards.
|
|
873
|
-
core.Guards.
|
|
1003
|
+
static toSigningBytes(header, payload) {
|
|
1004
|
+
core.Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
1005
|
+
core.Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
1006
|
+
const segments = [];
|
|
1007
|
+
const headerBytes = core.Converter.utf8ToBytes(JSON.stringify(header));
|
|
1008
|
+
segments.push(core.Converter.bytesToBase64Url(headerBytes));
|
|
1009
|
+
const payloadBytes = core.Converter.utf8ToBytes(JSON.stringify(payload));
|
|
1010
|
+
segments.push(core.Converter.bytesToBase64Url(payloadBytes));
|
|
1011
|
+
return core.Converter.utf8ToBytes(segments.join("."));
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Create header and payload from signing bytes.
|
|
1015
|
+
* @param signingBytes The signing bytes from a token.
|
|
1016
|
+
* @returns The header and payload.
|
|
1017
|
+
* @throws If the signing bytes are invalid
|
|
1018
|
+
*/
|
|
1019
|
+
static fromSigningBytes(signingBytes) {
|
|
1020
|
+
core.Guards.uint8Array(Jwt._CLASS_NAME, "signingBytes", signingBytes);
|
|
1021
|
+
const segments = core.Converter.bytesToUtf8(signingBytes).split(".");
|
|
1022
|
+
if (segments.length !== 2) {
|
|
1023
|
+
throw new core.GeneralError(Jwt._CLASS_NAME, "invalidSigningBytes");
|
|
1024
|
+
}
|
|
1025
|
+
const headerBytes = core.Converter.base64UrlToBytes(segments[0]);
|
|
1026
|
+
const payloadBytes = core.Converter.base64UrlToBytes(segments[1]);
|
|
1027
|
+
return {
|
|
1028
|
+
header: core.ObjectHelper.fromBytes(headerBytes),
|
|
1029
|
+
payload: core.ObjectHelper.fromBytes(payloadBytes)
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Convert signed bytes and signature bytes to token.
|
|
1034
|
+
* @param signingBytes The signed bytes.
|
|
1035
|
+
* @param signature The signature.
|
|
1036
|
+
* @returns The token.
|
|
1037
|
+
*/
|
|
1038
|
+
static tokenFromBytes(signingBytes, signature) {
|
|
1039
|
+
core.Guards.uint8Array(Jwt._CLASS_NAME, "signingBytes", signingBytes);
|
|
874
1040
|
core.Guards.uint8Array(Jwt._CLASS_NAME, "signature", signature);
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1041
|
+
const signedBytesUtf8 = core.Converter.bytesToUtf8(signingBytes);
|
|
1042
|
+
const signatureBase64 = core.Converter.bytesToBase64Url(signature);
|
|
1043
|
+
return `${signedBytesUtf8}.${signatureBase64}`;
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Convert the token to signing bytes and signature bytes.
|
|
1047
|
+
* @param token The token to convert to bytes.
|
|
1048
|
+
* @returns The decoded bytes.
|
|
1049
|
+
* @throws If the token is invalid.
|
|
1050
|
+
*/
|
|
1051
|
+
static tokenToBytes(token) {
|
|
1052
|
+
core.Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
1053
|
+
const segments = token.split(".");
|
|
1054
|
+
if (segments.length !== 3) {
|
|
1055
|
+
throw new core.GeneralError(Jwt._CLASS_NAME, "invalidTokenParts");
|
|
879
1056
|
}
|
|
880
|
-
|
|
1057
|
+
const signingBytes = core.Converter.utf8ToBytes(`${segments[0]}.${segments[1]}`);
|
|
1058
|
+
const signature = core.Converter.base64UrlToBytes(segments[2]);
|
|
1059
|
+
return {
|
|
1060
|
+
signingBytes,
|
|
1061
|
+
signature
|
|
1062
|
+
};
|
|
881
1063
|
}
|
|
882
1064
|
/**
|
|
883
1065
|
* Encode a token.
|
|
@@ -894,19 +1076,11 @@ class Jwt {
|
|
|
894
1076
|
if (!hasKey && !hasSigner) {
|
|
895
1077
|
throw new core.GeneralError(Jwt._CLASS_NAME, "noKeyOrSigner");
|
|
896
1078
|
}
|
|
897
|
-
signer ??= async (
|
|
1079
|
+
signer ??= async (h, p, k) => Jwt.defaultSigner(h, p, k);
|
|
898
1080
|
if (core.Is.undefined(header.typ)) {
|
|
899
1081
|
header.typ = "JWT";
|
|
900
1082
|
}
|
|
901
|
-
|
|
902
|
-
const headerBytes = core.Converter.utf8ToBytes(JSON.stringify(header));
|
|
903
|
-
segments.push(core.Converter.bytesToBase64Url(headerBytes));
|
|
904
|
-
const payloadBytes = core.Converter.utf8ToBytes(JSON.stringify(payload));
|
|
905
|
-
segments.push(core.Converter.bytesToBase64Url(payloadBytes));
|
|
906
|
-
const jwtHeaderAndPayload = core.Converter.utf8ToBytes(segments.join("."));
|
|
907
|
-
const sigBytes = await signer(header.alg, key, jwtHeaderAndPayload);
|
|
908
|
-
segments.push(core.Converter.bytesToBase64Url(sigBytes));
|
|
909
|
-
return segments.join(".");
|
|
1083
|
+
return signer(header, payload, key);
|
|
910
1084
|
}
|
|
911
1085
|
}
|
|
912
1086
|
|
|
@@ -922,7 +1096,7 @@ class MimeTypeHelper {
|
|
|
922
1096
|
* @returns The mime type if detected.
|
|
923
1097
|
*/
|
|
924
1098
|
static async detect(data) {
|
|
925
|
-
if (!core.Is.uint8Array(data)) {
|
|
1099
|
+
if (!core.Is.uint8Array(data) || data.length === 0) {
|
|
926
1100
|
return undefined;
|
|
927
1101
|
}
|
|
928
1102
|
// Image
|
|
@@ -994,12 +1168,13 @@ class MimeTypeHelper {
|
|
|
994
1168
|
[MimeTypes.Javascript]: "js",
|
|
995
1169
|
[MimeTypes.Json]: "json",
|
|
996
1170
|
[MimeTypes.JsonLd]: "jsonld",
|
|
1171
|
+
[MimeTypes.Jwt]: "jwt",
|
|
997
1172
|
[MimeTypes.Xml]: "xml",
|
|
998
1173
|
[MimeTypes.OctetStream]: "bin",
|
|
999
1174
|
[MimeTypes.Gzip]: "gzip",
|
|
1000
1175
|
[MimeTypes.Bzip2]: "bz2",
|
|
1001
1176
|
[MimeTypes.Zip]: "zip",
|
|
1002
|
-
[MimeTypes.Pdf]: "
|
|
1177
|
+
[MimeTypes.Pdf]: "pdf",
|
|
1003
1178
|
[MimeTypes.Gif]: "gif",
|
|
1004
1179
|
[MimeTypes.Bmp]: "bmp",
|
|
1005
1180
|
[MimeTypes.Jpeg]: "jpeg",
|
|
@@ -1050,7 +1225,8 @@ exports.FetchHelper = FetchHelper;
|
|
|
1050
1225
|
exports.HeaderTypes = HeaderTypes;
|
|
1051
1226
|
exports.HttpMethod = HttpMethod;
|
|
1052
1227
|
exports.HttpStatusCode = HttpStatusCode;
|
|
1228
|
+
exports.Jwk = Jwk;
|
|
1229
|
+
exports.Jws = Jws;
|
|
1053
1230
|
exports.Jwt = Jwt;
|
|
1054
|
-
exports.JwtAlgorithms = JwtAlgorithms;
|
|
1055
1231
|
exports.MimeTypeHelper = MimeTypeHelper;
|
|
1056
1232
|
exports.MimeTypes = MimeTypes;
|