1 module jwtlited.phobos; 2 3 public import jwtlited; 4 5 alias HS256Handler = HMACImpl!(JWTAlgorithm.HS256); 6 alias HS384Handler = HMACImpl!(JWTAlgorithm.HS384); 7 alias HS512Handler = HMACImpl!(JWTAlgorithm.HS512); 8 9 /** 10 * Implementation of HS256, HS384 and HS512 signing algorithms. 11 */ 12 private struct HMACImpl(JWTAlgorithm implAlg) 13 { 14 import std.digest.hmac : HMAC; 15 import std.digest.sha : SHA256, SHA384, SHA512; 16 17 static if (implAlg == JWTAlgorithm.HS256) { 18 enum signLen = 32; 19 alias SHA = SHA256; 20 } else static if (implAlg == JWTAlgorithm.HS384) { 21 enum signLen = 48; 22 alias SHA = SHA384; 23 } else static if (implAlg == JWTAlgorithm.HS512) { 24 enum signLen = 64; 25 alias SHA = SHA512; 26 } 27 else static assert(0, "Unsupprted algorithm for HMAC implementation"); 28 29 private const(ubyte)[] key; 30 31 bool loadKey(K)(K key) if (isToken!K) 32 { 33 if (!key.length) return false; 34 this.key = cast(const(ubyte)[])key; 35 return true; 36 } 37 38 bool isValidAlg(JWTAlgorithm alg) { return implAlg == alg; } 39 40 bool isValid(V, S)(V value, S sign) if (isToken!V && isToken!S) 41 { 42 assert(key.length, "Secret key not set"); 43 if (!key.length || !value.length || sign.length != signLen) return false; 44 45 immutable sig = HMAC!SHA(key) 46 .put(cast(const(ubyte)[])value) 47 .finish(); 48 assert(sig.length == signLen); 49 return cast(const(ubyte)[])sign == sig[]; 50 } 51 52 JWTAlgorithm signAlg() { return implAlg; } 53 54 int sign(S, V)(auto ref S sink, auto ref V value) if (isToken!V) 55 { 56 import std.range : put; 57 58 assert(key.length, "Secret key not set"); 59 if (!key.length || !value.length) return false; 60 61 put(sink, HMAC!SHA(key) 62 .put(cast(const(ubyte)[])value) 63 .finish()[]); 64 return signLen; 65 } 66 } 67 68 /// 69 @safe unittest 70 { 71 import jwtlited.phobos; 72 import std.stdio; 73 74 HS256Handler handler; 75 enum payload = `{"foo":42}`; 76 bool ret = handler.loadKey("foo bar baz"); 77 assert(ret); 78 char[512] tok; 79 immutable len = handler.encode(tok[], payload); 80 assert(len > 0); 81 writeln("HS256: ", tok[0..len]); 82 83 assert(handler.validate(tok[0..len])); 84 char[32] hdr, pay; 85 assert(handler.decode(tok[0..len], hdr[], pay[])); 86 assert(pay[0..payload.length] == payload); 87 } 88 89 @safe unittest 90 { 91 static assert(isValidator!HS256Handler); 92 static assert(isSigner!HS256Handler); 93 } 94 95 version (unittest) import jwtlited.tests; 96 97 @("Phobos tests") 98 @safe unittest 99 { 100 static void eval(H)(ref immutable TestCase tc) 101 { 102 H h; 103 assert(h.loadKey(tc.key) == !!(tc.valid & Valid.key)); 104 evalTest(h, tc); 105 } 106 107 import std.algorithm : canFind, filter; 108 109 with (JWTAlgorithm) 110 { 111 static immutable testAlgs = [HS256, HS384, HS512]; 112 113 foreach (tc; testCases.filter!(a => testAlgs.canFind(a.alg))) 114 { 115 switch (tc.alg) 116 { 117 case HS256: eval!HS256Handler(tc); break; 118 case HS384: eval!HS384Handler(tc); break; 119 case HS512: eval!HS512Handler(tc); break; 120 default: assert(0); 121 } 122 } 123 } 124 }