@twin.org/web 0.0.1-next.4 → 0.0.1-next.41
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 +251 -96
- package/dist/esm/index.mjs +252 -98
- 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/jwk.d.ts +25 -0
- package/dist/types/utils/jws.d.ts +20 -0
- package/dist/types/utils/jwt.d.ts +67 -29
- package/docs/changelog.md +1 -1
- package/docs/reference/classes/FetchError.md +13 -5
- package/docs/reference/classes/FetchHelper.md +51 -17
- package/docs/reference/classes/Jwk.md +79 -0
- package/docs/reference/classes/Jws.md +75 -0
- package/docs/reference/classes/Jwt.md +222 -102
- package/docs/reference/classes/MimeTypeHelper.md +6 -2
- 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 +4 -24
- package/docs/reference/interfaces/IJwtPayload.md +4 -56
- package/docs/reference/type-aliases/JwkCryptoKey.md +5 -0
- 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/esm/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { BaseError, StringHelper, Guards, Is, AsyncCache, ObjectHelper,
|
|
2
|
-
import {
|
|
1
|
+
import { BaseError, StringHelper, Guards, Is, AsyncCache, ObjectHelper, GeneralError, Converter } from '@twin.org/core';
|
|
2
|
+
import { Ed25519 } from '@twin.org/crypto';
|
|
3
|
+
import { importJWK, CompactSign, flattenedVerify, SignJWT, jwtVerify } from 'jose';
|
|
3
4
|
|
|
4
5
|
// Copyright 2024 IOTA Stiftung.
|
|
5
6
|
// SPDX-License-Identifier: Apache-2.0.
|
|
@@ -37,35 +38,35 @@ const HeaderTypes = {
|
|
|
37
38
|
/**
|
|
38
39
|
* Content Type.
|
|
39
40
|
*/
|
|
40
|
-
ContentType: "
|
|
41
|
+
ContentType: "content-type",
|
|
41
42
|
/**
|
|
42
43
|
* Content Length.
|
|
43
44
|
*/
|
|
44
|
-
ContentLength: "
|
|
45
|
+
ContentLength: "content-length",
|
|
45
46
|
/**
|
|
46
47
|
* Content Disposition.
|
|
47
48
|
*/
|
|
48
|
-
ContentDisposition: "
|
|
49
|
+
ContentDisposition: "content-disposition",
|
|
49
50
|
/**
|
|
50
51
|
* Accept.
|
|
51
52
|
*/
|
|
52
|
-
Accept: "
|
|
53
|
+
Accept: "accept",
|
|
53
54
|
/**
|
|
54
55
|
* Authorization.
|
|
55
56
|
*/
|
|
56
|
-
Authorization: "
|
|
57
|
+
Authorization: "authorization",
|
|
57
58
|
/**
|
|
58
59
|
* Cookie.
|
|
59
60
|
*/
|
|
60
|
-
Cookie: "
|
|
61
|
+
Cookie: "cookie",
|
|
61
62
|
/**
|
|
62
63
|
* Set Cookie.
|
|
63
64
|
*/
|
|
64
|
-
SetCookie: "
|
|
65
|
+
SetCookie: "set-cookie",
|
|
65
66
|
/**
|
|
66
67
|
* Location
|
|
67
68
|
*/
|
|
68
|
-
Location: "
|
|
69
|
+
Location: "location"
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
// Copyright 2024 IOTA Stiftung.
|
|
@@ -343,23 +344,6 @@ const HttpStatusCode = {
|
|
|
343
344
|
networkAuthenticationRequired: 511
|
|
344
345
|
};
|
|
345
346
|
|
|
346
|
-
// Copyright 2024 IOTA Stiftung.
|
|
347
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
348
|
-
/**
|
|
349
|
-
* The cryptographic algorithms supported for JSON Web Tokens and JSON Web Keys.
|
|
350
|
-
*/
|
|
351
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
352
|
-
const JwtAlgorithms = {
|
|
353
|
-
/**
|
|
354
|
-
* HMAC using SHA-256.
|
|
355
|
-
*/
|
|
356
|
-
HS256: "HS256",
|
|
357
|
-
/**
|
|
358
|
-
* EdDSA using Ed25519.
|
|
359
|
-
*/
|
|
360
|
-
EdDSA: "EdDSA"
|
|
361
|
-
};
|
|
362
|
-
|
|
363
347
|
// Copyright 2024 IOTA Stiftung.
|
|
364
348
|
// SPDX-License-Identifier: Apache-2.0.
|
|
365
349
|
/**
|
|
@@ -387,6 +371,10 @@ const MimeTypes = {
|
|
|
387
371
|
* JSON-LD - application/ld+json
|
|
388
372
|
*/
|
|
389
373
|
JsonLd: "application/ld+json",
|
|
374
|
+
/**
|
|
375
|
+
* JWT - application/jwt
|
|
376
|
+
*/
|
|
377
|
+
Jwt: "application/jwt",
|
|
390
378
|
/**
|
|
391
379
|
* XML - application/xml
|
|
392
380
|
*/
|
|
@@ -708,7 +696,134 @@ class FetchHelper {
|
|
|
708
696
|
// Copyright 2024 IOTA Stiftung.
|
|
709
697
|
// SPDX-License-Identifier: Apache-2.0.
|
|
710
698
|
/**
|
|
711
|
-
* Class to
|
|
699
|
+
* Class to handle JSON Web Keys.
|
|
700
|
+
*/
|
|
701
|
+
class Jwk {
|
|
702
|
+
/**
|
|
703
|
+
* Runtime name for the class.
|
|
704
|
+
* @internal
|
|
705
|
+
*/
|
|
706
|
+
static _CLASS_NAME = "Jwk";
|
|
707
|
+
/**
|
|
708
|
+
* Convert the JWK to a crypto key.
|
|
709
|
+
* @param jwk The JWK to convert.
|
|
710
|
+
* @returns The crypto key.
|
|
711
|
+
*/
|
|
712
|
+
static async toCryptoKey(jwk) {
|
|
713
|
+
Guards.object(Jwk._CLASS_NAME, "jwk", jwk);
|
|
714
|
+
try {
|
|
715
|
+
return importJWK(jwk);
|
|
716
|
+
}
|
|
717
|
+
catch (err) {
|
|
718
|
+
throw new GeneralError(Jwk._CLASS_NAME, "jwkImportFailed", undefined, err);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Convert the Ed25519 private key to a crypto key.
|
|
723
|
+
* @param privateKey The private key to use.
|
|
724
|
+
* @returns The crypto key.
|
|
725
|
+
*/
|
|
726
|
+
static async fromEd25519Private(privateKey) {
|
|
727
|
+
Guards.uint8Array(Jwk._CLASS_NAME, "privateKey", privateKey);
|
|
728
|
+
try {
|
|
729
|
+
const publicKey = Ed25519.publicKeyFromPrivateKey(privateKey);
|
|
730
|
+
const jwk = {
|
|
731
|
+
kty: "OKP",
|
|
732
|
+
use: "sig",
|
|
733
|
+
alg: "EdDSA",
|
|
734
|
+
crv: "Ed25519",
|
|
735
|
+
x: Converter.bytesToBase64Url(publicKey),
|
|
736
|
+
d: Converter.bytesToBase64Url(privateKey)
|
|
737
|
+
};
|
|
738
|
+
return importJWK(jwk);
|
|
739
|
+
}
|
|
740
|
+
catch (err) {
|
|
741
|
+
throw new GeneralError(Jwk._CLASS_NAME, "jwkImportFailed", undefined, err);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Convert the Ed25519 public key to a crypto key.
|
|
746
|
+
* @param publicKey The private key to use.
|
|
747
|
+
* @returns The crypto key.
|
|
748
|
+
*/
|
|
749
|
+
static async fromEd25519Public(publicKey) {
|
|
750
|
+
Guards.uint8Array(Jwk._CLASS_NAME, "publicKey", publicKey);
|
|
751
|
+
try {
|
|
752
|
+
const jwk = {
|
|
753
|
+
kty: "OKP",
|
|
754
|
+
use: "sig",
|
|
755
|
+
alg: "EdDSA",
|
|
756
|
+
crv: "Ed25519",
|
|
757
|
+
x: Converter.bytesToBase64Url(publicKey)
|
|
758
|
+
};
|
|
759
|
+
return importJWK(jwk);
|
|
760
|
+
}
|
|
761
|
+
catch (err) {
|
|
762
|
+
throw new GeneralError(Jwk._CLASS_NAME, "jwkImportFailed", undefined, err);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Copyright 2024 IOTA Stiftung.
|
|
768
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
769
|
+
/**
|
|
770
|
+
* Class to handle JSON Web Signatures.
|
|
771
|
+
*/
|
|
772
|
+
class Jws {
|
|
773
|
+
/**
|
|
774
|
+
* Runtime name for the class.
|
|
775
|
+
* @internal
|
|
776
|
+
*/
|
|
777
|
+
static _CLASS_NAME = "Jws";
|
|
778
|
+
/**
|
|
779
|
+
* Create a signature.
|
|
780
|
+
* @param privateKey The private key to use.
|
|
781
|
+
* @param hash The hash to sign.
|
|
782
|
+
* @returns The signature.
|
|
783
|
+
*/
|
|
784
|
+
static async create(privateKey, hash) {
|
|
785
|
+
Guards.defined(Jws._CLASS_NAME, "privateKey", privateKey);
|
|
786
|
+
Guards.uint8Array(Jws._CLASS_NAME, "hash", hash);
|
|
787
|
+
try {
|
|
788
|
+
const jws = await new CompactSign(hash)
|
|
789
|
+
.setProtectedHeader({
|
|
790
|
+
alg: privateKey.algorithm.name,
|
|
791
|
+
b64: false,
|
|
792
|
+
crit: ["b64"]
|
|
793
|
+
})
|
|
794
|
+
.sign(privateKey);
|
|
795
|
+
return jws;
|
|
796
|
+
}
|
|
797
|
+
catch (err) {
|
|
798
|
+
throw new GeneralError(Jws._CLASS_NAME, "createFailed", undefined, err);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Verify a signature.
|
|
803
|
+
* @param jws The signature to verify.
|
|
804
|
+
* @param publicKey The public key to verify the signature with.
|
|
805
|
+
* @param hash The hash to verify.
|
|
806
|
+
* @returns True if the signature was verified.
|
|
807
|
+
*/
|
|
808
|
+
static async verify(jws, publicKey, hash) {
|
|
809
|
+
Guards.stringValue(Jws._CLASS_NAME, "jws", jws);
|
|
810
|
+
Guards.defined(Jws._CLASS_NAME, "publicKey", publicKey);
|
|
811
|
+
Guards.uint8Array(Jws._CLASS_NAME, "hash", hash);
|
|
812
|
+
try {
|
|
813
|
+
const jwsParts = jws.split(".");
|
|
814
|
+
await flattenedVerify({ protected: jwsParts[0], payload: hash, signature: jwsParts[2] }, publicKey);
|
|
815
|
+
return true;
|
|
816
|
+
}
|
|
817
|
+
catch (err) {
|
|
818
|
+
throw new GeneralError(Jws._CLASS_NAME, "verifyFailed", undefined, err);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Copyright 2024 IOTA Stiftung.
|
|
824
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
825
|
+
/**
|
|
826
|
+
* Class to handle JSON Web Tokens.
|
|
712
827
|
*/
|
|
713
828
|
class Jwt {
|
|
714
829
|
/**
|
|
@@ -725,9 +840,8 @@ class Jwt {
|
|
|
725
840
|
*/
|
|
726
841
|
static async encode(header, payload, key) {
|
|
727
842
|
Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
728
|
-
Guards.arrayOneOf(Jwt._CLASS_NAME, "header.alg", header.alg, Object.values(JwtAlgorithms));
|
|
729
843
|
Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
730
|
-
Guards.
|
|
844
|
+
Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
731
845
|
return Jwt.internalEncode(header, payload, key);
|
|
732
846
|
}
|
|
733
847
|
/**
|
|
@@ -739,7 +853,7 @@ class Jwt {
|
|
|
739
853
|
*/
|
|
740
854
|
static async encodeWithSigner(header, payload, signer) {
|
|
741
855
|
Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
742
|
-
Guards.
|
|
856
|
+
Guards.stringValue(Jwt._CLASS_NAME, "header.alg", header.alg);
|
|
743
857
|
Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
744
858
|
Guards.function(Jwt._CLASS_NAME, "signer", signer);
|
|
745
859
|
return Jwt.internalEncode(header, payload, undefined, signer);
|
|
@@ -786,13 +900,8 @@ class Jwt {
|
|
|
786
900
|
*/
|
|
787
901
|
static async verify(token, key) {
|
|
788
902
|
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
789
|
-
Guards.
|
|
790
|
-
|
|
791
|
-
const verified = await Jwt.verifySignature(decoded.header, decoded.payload, decoded.signature, key);
|
|
792
|
-
return {
|
|
793
|
-
verified,
|
|
794
|
-
...decoded
|
|
795
|
-
};
|
|
903
|
+
Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
904
|
+
return Jwt.verifySignature(token, key);
|
|
796
905
|
}
|
|
797
906
|
/**
|
|
798
907
|
* Verify a token.
|
|
@@ -803,79 +912,131 @@ class Jwt {
|
|
|
803
912
|
static async verifyWithVerifier(token, verifier) {
|
|
804
913
|
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
805
914
|
Guards.function(Jwt._CLASS_NAME, "verifier", verifier);
|
|
806
|
-
|
|
807
|
-
const decoded = await Jwt.decode(token);
|
|
808
|
-
const verified = await Jwt.verifySignature(decoded.header, decoded.payload, decoded.signature, undefined, verifier);
|
|
809
|
-
return {
|
|
810
|
-
verified,
|
|
811
|
-
...decoded
|
|
812
|
-
};
|
|
915
|
+
return Jwt.verifySignature(token, undefined, verifier);
|
|
813
916
|
}
|
|
814
917
|
/**
|
|
815
918
|
* Verify a token by parts.
|
|
816
|
-
* @param
|
|
817
|
-
* @param payload The payload to verify.
|
|
818
|
-
* @param signature The signature to verify.
|
|
919
|
+
* @param token The token to verify.
|
|
819
920
|
* @param key The key for verifying the token, if not provided no verification occurs.
|
|
820
921
|
* @param verifier Custom verification method.
|
|
821
922
|
* @returns True if the parts are verified.
|
|
822
923
|
*/
|
|
823
|
-
static async verifySignature(
|
|
924
|
+
static async verifySignature(token, key, verifier) {
|
|
925
|
+
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
824
926
|
const hasKey = Is.notEmpty(key);
|
|
825
927
|
const hasVerifier = Is.notEmpty(verifier);
|
|
826
928
|
if (!hasKey && !hasVerifier) {
|
|
827
929
|
throw new GeneralError(Jwt._CLASS_NAME, "noKeyOrVerifier");
|
|
828
930
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
Is.object(payload) &&
|
|
832
|
-
Is.uint8Array(signature) &&
|
|
833
|
-
Is.arrayOneOf(header.alg, Object.values(JwtAlgorithms))) {
|
|
834
|
-
const segments = [];
|
|
835
|
-
const headerBytes = Converter.utf8ToBytes(JSON.stringify(header));
|
|
836
|
-
segments.push(Converter.bytesToBase64Url(headerBytes));
|
|
837
|
-
const payloadBytes = Converter.utf8ToBytes(JSON.stringify(payload));
|
|
838
|
-
segments.push(Converter.bytesToBase64Url(payloadBytes));
|
|
839
|
-
const jwtHeaderAndPayload = Converter.utf8ToBytes(segments.join("."));
|
|
840
|
-
verifier ??= async (alg, k, p, s) => Jwt.defaultVerifier(alg, k, p, s);
|
|
841
|
-
verified = await verifier(header.alg, key, jwtHeaderAndPayload, signature);
|
|
842
|
-
}
|
|
843
|
-
return verified;
|
|
931
|
+
verifier ??= async (t, k) => Jwt.defaultVerifier(t, k);
|
|
932
|
+
return verifier(token, key);
|
|
844
933
|
}
|
|
845
934
|
/**
|
|
846
935
|
* The default signer for the JWT.
|
|
847
|
-
* @param
|
|
848
|
-
* @param key The key to sign with.
|
|
936
|
+
* @param header The header to sign.
|
|
849
937
|
* @param payload The payload to sign.
|
|
938
|
+
* @param key The optional key to sign with.
|
|
850
939
|
* @returns The signature.
|
|
851
940
|
*/
|
|
852
|
-
static async defaultSigner(
|
|
853
|
-
Guards.
|
|
854
|
-
Guards.
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
941
|
+
static async defaultSigner(header, payload, key) {
|
|
942
|
+
Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
943
|
+
Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
944
|
+
Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
945
|
+
const signer = new SignJWT(payload);
|
|
946
|
+
signer.setProtectedHeader(header);
|
|
947
|
+
let finalKey = key;
|
|
948
|
+
if (header.alg === "EdDSA" && Is.uint8Array(key)) {
|
|
949
|
+
// Jose does not support Ed25519 keys in raw format, so we need to convert it to PKCS8.
|
|
950
|
+
finalKey = await Ed25519.privateKeyToPKCS8(key);
|
|
858
951
|
}
|
|
859
|
-
return
|
|
952
|
+
return signer.sign(finalKey);
|
|
860
953
|
}
|
|
861
954
|
/**
|
|
862
955
|
* The default verifier for the JWT.
|
|
863
|
-
* @param
|
|
956
|
+
* @param token The token to verify.
|
|
864
957
|
* @param key The key to verify with.
|
|
865
|
-
* @
|
|
866
|
-
|
|
867
|
-
|
|
958
|
+
* @returns The header and payload if verification successful.
|
|
959
|
+
*/
|
|
960
|
+
static async defaultVerifier(token, key) {
|
|
961
|
+
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
962
|
+
Guards.defined(Jwt._CLASS_NAME, "key", key);
|
|
963
|
+
try {
|
|
964
|
+
const result = await jwtVerify(token, key);
|
|
965
|
+
return {
|
|
966
|
+
header: result.protectedHeader,
|
|
967
|
+
payload: result.payload
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
catch (err) {
|
|
971
|
+
throw new GeneralError(Jwt._CLASS_NAME, "verifyFailed", undefined, err);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Create bytes for signing from header and payload.
|
|
976
|
+
* @param header The header.
|
|
977
|
+
* @param payload The payload.
|
|
978
|
+
* @returns The bytes to sign.
|
|
979
|
+
*/
|
|
980
|
+
static toSigningBytes(header, payload) {
|
|
981
|
+
Guards.object(Jwt._CLASS_NAME, "header", header);
|
|
982
|
+
Guards.object(Jwt._CLASS_NAME, "payload", payload);
|
|
983
|
+
const segments = [];
|
|
984
|
+
const headerBytes = Converter.utf8ToBytes(JSON.stringify(header));
|
|
985
|
+
segments.push(Converter.bytesToBase64Url(headerBytes));
|
|
986
|
+
const payloadBytes = Converter.utf8ToBytes(JSON.stringify(payload));
|
|
987
|
+
segments.push(Converter.bytesToBase64Url(payloadBytes));
|
|
988
|
+
return Converter.utf8ToBytes(segments.join("."));
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Create header and payload from signing bytes.
|
|
992
|
+
* @param signingBytes The signing bytes from a token.
|
|
993
|
+
* @returns The header and payload.
|
|
994
|
+
* @throws If the signing bytes are invalid
|
|
995
|
+
*/
|
|
996
|
+
static fromSigningBytes(signingBytes) {
|
|
997
|
+
Guards.uint8Array(Jwt._CLASS_NAME, "signingBytes", signingBytes);
|
|
998
|
+
const segments = Converter.bytesToUtf8(signingBytes).split(".");
|
|
999
|
+
if (segments.length !== 2) {
|
|
1000
|
+
throw new GeneralError(Jwt._CLASS_NAME, "invalidSigningBytes");
|
|
1001
|
+
}
|
|
1002
|
+
const headerBytes = Converter.base64UrlToBytes(segments[0]);
|
|
1003
|
+
const payloadBytes = Converter.base64UrlToBytes(segments[1]);
|
|
1004
|
+
return {
|
|
1005
|
+
header: ObjectHelper.fromBytes(headerBytes),
|
|
1006
|
+
payload: ObjectHelper.fromBytes(payloadBytes)
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Convert signed bytes and signature bytes to token.
|
|
1011
|
+
* @param signingBytes The signed bytes.
|
|
1012
|
+
* @param signature The signature.
|
|
1013
|
+
* @returns The token.
|
|
868
1014
|
*/
|
|
869
|
-
static
|
|
870
|
-
Guards.uint8Array(Jwt._CLASS_NAME, "
|
|
871
|
-
Guards.uint8Array(Jwt._CLASS_NAME, "payload", payload);
|
|
1015
|
+
static tokenFromBytes(signingBytes, signature) {
|
|
1016
|
+
Guards.uint8Array(Jwt._CLASS_NAME, "signingBytes", signingBytes);
|
|
872
1017
|
Guards.uint8Array(Jwt._CLASS_NAME, "signature", signature);
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
1018
|
+
const signedBytesUtf8 = Converter.bytesToUtf8(signingBytes);
|
|
1019
|
+
const signatureBase64 = Converter.bytesToBase64Url(signature);
|
|
1020
|
+
return `${signedBytesUtf8}.${signatureBase64}`;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Convert the token to signing bytes and signature bytes.
|
|
1024
|
+
* @param token The token to convert to bytes.
|
|
1025
|
+
* @returns The decoded bytes.
|
|
1026
|
+
* @throws If the token is invalid.
|
|
1027
|
+
*/
|
|
1028
|
+
static tokenToBytes(token) {
|
|
1029
|
+
Guards.stringValue(Jwt._CLASS_NAME, "token", token);
|
|
1030
|
+
const segments = token.split(".");
|
|
1031
|
+
if (segments.length !== 3) {
|
|
1032
|
+
throw new GeneralError(Jwt._CLASS_NAME, "invalidTokenParts");
|
|
877
1033
|
}
|
|
878
|
-
|
|
1034
|
+
const signingBytes = Converter.utf8ToBytes(`${segments[0]}.${segments[1]}`);
|
|
1035
|
+
const signature = Converter.base64UrlToBytes(segments[2]);
|
|
1036
|
+
return {
|
|
1037
|
+
signingBytes,
|
|
1038
|
+
signature
|
|
1039
|
+
};
|
|
879
1040
|
}
|
|
880
1041
|
/**
|
|
881
1042
|
* Encode a token.
|
|
@@ -892,19 +1053,11 @@ class Jwt {
|
|
|
892
1053
|
if (!hasKey && !hasSigner) {
|
|
893
1054
|
throw new GeneralError(Jwt._CLASS_NAME, "noKeyOrSigner");
|
|
894
1055
|
}
|
|
895
|
-
signer ??= async (
|
|
1056
|
+
signer ??= async (h, p, k) => Jwt.defaultSigner(h, p, k);
|
|
896
1057
|
if (Is.undefined(header.typ)) {
|
|
897
1058
|
header.typ = "JWT";
|
|
898
1059
|
}
|
|
899
|
-
|
|
900
|
-
const headerBytes = Converter.utf8ToBytes(JSON.stringify(header));
|
|
901
|
-
segments.push(Converter.bytesToBase64Url(headerBytes));
|
|
902
|
-
const payloadBytes = Converter.utf8ToBytes(JSON.stringify(payload));
|
|
903
|
-
segments.push(Converter.bytesToBase64Url(payloadBytes));
|
|
904
|
-
const jwtHeaderAndPayload = Converter.utf8ToBytes(segments.join("."));
|
|
905
|
-
const sigBytes = await signer(header.alg, key, jwtHeaderAndPayload);
|
|
906
|
-
segments.push(Converter.bytesToBase64Url(sigBytes));
|
|
907
|
-
return segments.join(".");
|
|
1060
|
+
return signer(header, payload, key);
|
|
908
1061
|
}
|
|
909
1062
|
}
|
|
910
1063
|
|
|
@@ -920,7 +1073,7 @@ class MimeTypeHelper {
|
|
|
920
1073
|
* @returns The mime type if detected.
|
|
921
1074
|
*/
|
|
922
1075
|
static async detect(data) {
|
|
923
|
-
if (!Is.uint8Array(data)) {
|
|
1076
|
+
if (!Is.uint8Array(data) || data.length === 0) {
|
|
924
1077
|
return undefined;
|
|
925
1078
|
}
|
|
926
1079
|
// Image
|
|
@@ -992,12 +1145,13 @@ class MimeTypeHelper {
|
|
|
992
1145
|
[MimeTypes.Javascript]: "js",
|
|
993
1146
|
[MimeTypes.Json]: "json",
|
|
994
1147
|
[MimeTypes.JsonLd]: "jsonld",
|
|
1148
|
+
[MimeTypes.Jwt]: "jwt",
|
|
995
1149
|
[MimeTypes.Xml]: "xml",
|
|
996
1150
|
[MimeTypes.OctetStream]: "bin",
|
|
997
1151
|
[MimeTypes.Gzip]: "gzip",
|
|
998
1152
|
[MimeTypes.Bzip2]: "bz2",
|
|
999
1153
|
[MimeTypes.Zip]: "zip",
|
|
1000
|
-
[MimeTypes.Pdf]: "
|
|
1154
|
+
[MimeTypes.Pdf]: "pdf",
|
|
1001
1155
|
[MimeTypes.Gif]: "gif",
|
|
1002
1156
|
[MimeTypes.Bmp]: "bmp",
|
|
1003
1157
|
[MimeTypes.Jpeg]: "jpeg",
|
|
@@ -1043,4 +1197,4 @@ class MimeTypeHelper {
|
|
|
1043
1197
|
}
|
|
1044
1198
|
}
|
|
1045
1199
|
|
|
1046
|
-
export { FetchError, FetchHelper, HeaderTypes, HttpMethod, HttpStatusCode,
|
|
1200
|
+
export { FetchError, FetchHelper, HeaderTypes, HttpMethod, HttpStatusCode, Jwk, Jws, Jwt, MimeTypeHelper, MimeTypes };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,8 +7,10 @@ export * from "./models/IHttpHeaders";
|
|
|
7
7
|
export * from "./models/IJwk";
|
|
8
8
|
export * from "./models/IJwtHeader";
|
|
9
9
|
export * from "./models/IJwtPayload";
|
|
10
|
-
export * from "./models/
|
|
10
|
+
export * from "./models/jwkCryptoKey";
|
|
11
11
|
export * from "./models/mimeTypes";
|
|
12
12
|
export * from "./utils/fetchHelper";
|
|
13
|
+
export * from "./utils/jwk";
|
|
14
|
+
export * from "./utils/jws";
|
|
13
15
|
export * from "./utils/jwt";
|
|
14
16
|
export * from "./utils/mimeTypeHelper";
|
|
@@ -1,62 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JWK } from "jose";
|
|
2
2
|
/**
|
|
3
3
|
* The fields in a JSON Web Key.
|
|
4
4
|
*/
|
|
5
|
-
export interface IJwk {
|
|
6
|
-
/**
|
|
7
|
-
* Additional fields in the key.
|
|
8
|
-
*/
|
|
9
|
-
[key: string]: unknown;
|
|
10
|
-
/**
|
|
11
|
-
* The cryptographic algorithm for the key.
|
|
12
|
-
*/
|
|
13
|
-
alg?: JwtAlgorithms;
|
|
14
|
-
/**
|
|
15
|
-
* The intended use for the key.
|
|
16
|
-
*/
|
|
17
|
-
use?: string;
|
|
18
|
-
/**
|
|
19
|
-
* The operation(s) that the key is intended to be used for.
|
|
20
|
-
*/
|
|
21
|
-
key_ops?: string[];
|
|
22
|
-
/**
|
|
23
|
-
* The key type parameter.
|
|
24
|
-
*/
|
|
25
|
-
kty: string;
|
|
26
|
-
/**
|
|
27
|
-
* The public key parameters.
|
|
28
|
-
*/
|
|
29
|
-
n?: string;
|
|
30
|
-
/**
|
|
31
|
-
* Exponent parameter.
|
|
32
|
-
*/
|
|
33
|
-
e?: string;
|
|
34
|
-
/**
|
|
35
|
-
* The private key parameters.
|
|
36
|
-
*/
|
|
37
|
-
d?: string;
|
|
38
|
-
/**
|
|
39
|
-
* The private key parameters.
|
|
40
|
-
*/
|
|
41
|
-
p?: string;
|
|
42
|
-
/**
|
|
43
|
-
* The private key parameters.
|
|
44
|
-
*/
|
|
45
|
-
q?: string;
|
|
46
|
-
/**
|
|
47
|
-
* The private key parameters.
|
|
48
|
-
*/
|
|
49
|
-
dp?: string;
|
|
50
|
-
/**
|
|
51
|
-
* The private key parameters.
|
|
52
|
-
*/
|
|
53
|
-
dq?: string;
|
|
54
|
-
/**
|
|
55
|
-
* The private key parameters.
|
|
56
|
-
*/
|
|
57
|
-
qi?: string;
|
|
58
|
-
/**
|
|
59
|
-
* The key ID.
|
|
60
|
-
*/
|
|
61
|
-
kid?: string;
|
|
5
|
+
export interface IJwk extends JWK {
|
|
62
6
|
}
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JWTHeaderParameters } from "jose";
|
|
2
2
|
/**
|
|
3
3
|
* The fields in a JSON Web Token header.
|
|
4
4
|
*/
|
|
5
|
-
export interface IJwtHeader {
|
|
6
|
-
/**
|
|
7
|
-
* Additional fields in the header.
|
|
8
|
-
*/
|
|
9
|
-
[key: string]: unknown;
|
|
10
|
-
/**
|
|
11
|
-
* The type of the token.
|
|
12
|
-
*/
|
|
13
|
-
typ?: string;
|
|
14
|
-
/**
|
|
15
|
-
* The algorithm used to sign the token.
|
|
16
|
-
*/
|
|
17
|
-
alg: JwtAlgorithms;
|
|
18
|
-
/**
|
|
19
|
-
* The key ID.
|
|
20
|
-
*/
|
|
21
|
-
kid?: string;
|
|
5
|
+
export interface IJwtHeader extends JWTHeaderParameters {
|
|
22
6
|
}
|
|
@@ -1,37 +1,6 @@
|
|
|
1
|
+
import type { JWTPayload } from "jose";
|
|
1
2
|
/**
|
|
2
3
|
* The fields in a JSON Web Token payload.
|
|
3
4
|
*/
|
|
4
|
-
export interface IJwtPayload {
|
|
5
|
-
/**
|
|
6
|
-
* Additional fields in the payload.
|
|
7
|
-
*/
|
|
8
|
-
[key: string]: unknown;
|
|
9
|
-
/**
|
|
10
|
-
* The issuer of the token.
|
|
11
|
-
*/
|
|
12
|
-
iss?: string;
|
|
13
|
-
/**
|
|
14
|
-
* The subject of the token.
|
|
15
|
-
*/
|
|
16
|
-
sub?: string;
|
|
17
|
-
/**
|
|
18
|
-
* The audience of the token.
|
|
19
|
-
*/
|
|
20
|
-
aud?: string;
|
|
21
|
-
/**
|
|
22
|
-
* The expiration time of the token.
|
|
23
|
-
*/
|
|
24
|
-
exp?: number;
|
|
25
|
-
/**
|
|
26
|
-
* The not before time of the token.
|
|
27
|
-
*/
|
|
28
|
-
nbf?: number;
|
|
29
|
-
/**
|
|
30
|
-
* The issued at time of the token.
|
|
31
|
-
*/
|
|
32
|
-
iat?: number;
|
|
33
|
-
/**
|
|
34
|
-
* The JWT ID.
|
|
35
|
-
*/
|
|
36
|
-
jti?: string;
|
|
5
|
+
export interface IJwtPayload extends JWTPayload {
|
|
37
6
|
}
|
|
@@ -5,35 +5,35 @@ export declare const HeaderTypes: {
|
|
|
5
5
|
/**
|
|
6
6
|
* Content Type.
|
|
7
7
|
*/
|
|
8
|
-
readonly ContentType: "
|
|
8
|
+
readonly ContentType: "content-type";
|
|
9
9
|
/**
|
|
10
10
|
* Content Length.
|
|
11
11
|
*/
|
|
12
|
-
readonly ContentLength: "
|
|
12
|
+
readonly ContentLength: "content-length";
|
|
13
13
|
/**
|
|
14
14
|
* Content Disposition.
|
|
15
15
|
*/
|
|
16
|
-
readonly ContentDisposition: "
|
|
16
|
+
readonly ContentDisposition: "content-disposition";
|
|
17
17
|
/**
|
|
18
18
|
* Accept.
|
|
19
19
|
*/
|
|
20
|
-
readonly Accept: "
|
|
20
|
+
readonly Accept: "accept";
|
|
21
21
|
/**
|
|
22
22
|
* Authorization.
|
|
23
23
|
*/
|
|
24
|
-
readonly Authorization: "
|
|
24
|
+
readonly Authorization: "authorization";
|
|
25
25
|
/**
|
|
26
26
|
* Cookie.
|
|
27
27
|
*/
|
|
28
|
-
readonly Cookie: "
|
|
28
|
+
readonly Cookie: "cookie";
|
|
29
29
|
/**
|
|
30
30
|
* Set Cookie.
|
|
31
31
|
*/
|
|
32
|
-
readonly SetCookie: "
|
|
32
|
+
readonly SetCookie: "set-cookie";
|
|
33
33
|
/**
|
|
34
34
|
* Location
|
|
35
35
|
*/
|
|
36
|
-
readonly Location: "
|
|
36
|
+
readonly Location: "location";
|
|
37
37
|
};
|
|
38
38
|
/**
|
|
39
39
|
* Common http header types.
|