xref: /haiku/src/apps/haikudepot/server/JwtTokenHelper.cpp (revision 4b347fccb28bb9f7242ba8bff1f49671247a7a75)
1*4b347fccSAndrew Lindesay /*
2*4b347fccSAndrew Lindesay  * Copyright 2023, Andrew Lindesay <apl@lindesay.co.nz>.
3*4b347fccSAndrew Lindesay  * All rights reserved. Distributed under the terms of the MIT License.
4*4b347fccSAndrew Lindesay  */
5*4b347fccSAndrew Lindesay 
6*4b347fccSAndrew Lindesay 
7*4b347fccSAndrew Lindesay #include "JwtTokenHelper.h"
8*4b347fccSAndrew Lindesay 
9*4b347fccSAndrew Lindesay #include "DataIOUtils.h"
10*4b347fccSAndrew Lindesay #include "Json.h"
11*4b347fccSAndrew Lindesay #include "JsonMessageWriter.h"
12*4b347fccSAndrew Lindesay 
13*4b347fccSAndrew Lindesay #include <ctype.h>
14*4b347fccSAndrew Lindesay 
15*4b347fccSAndrew Lindesay 
16*4b347fccSAndrew Lindesay /*static*/ bool
IsValid(const BString & value)17*4b347fccSAndrew Lindesay JwtTokenHelper::IsValid(const BString& value)
18*4b347fccSAndrew Lindesay {
19*4b347fccSAndrew Lindesay 	int countDots = 0;
20*4b347fccSAndrew Lindesay 
21*4b347fccSAndrew Lindesay 	for (int i = 0; i < value.Length(); i++) {
22*4b347fccSAndrew Lindesay 		char ch = value[i];
23*4b347fccSAndrew Lindesay 
24*4b347fccSAndrew Lindesay 		if ('.' == ch)
25*4b347fccSAndrew Lindesay 			countDots++;
26*4b347fccSAndrew Lindesay 		else {
27*4b347fccSAndrew Lindesay 			if (!_IsBase64(ch))
28*4b347fccSAndrew Lindesay 				return false;
29*4b347fccSAndrew Lindesay 		}
30*4b347fccSAndrew Lindesay 	}
31*4b347fccSAndrew Lindesay 
32*4b347fccSAndrew Lindesay 	return 2 == countDots;
33*4b347fccSAndrew Lindesay }
34*4b347fccSAndrew Lindesay 
35*4b347fccSAndrew Lindesay 
36*4b347fccSAndrew Lindesay /*! A JWT token is split into three parts separated by a '.' character. The
37*4b347fccSAndrew Lindesay     middle section is a base-64 encoded string and within the string is JSON
38*4b347fccSAndrew Lindesay     structured data. The JSON data contains key-value pairs which carry data
39*4b347fccSAndrew Lindesay     about the token. This method will take a JWT token, will find the middle
40*4b347fccSAndrew Lindesay     section and will parse the claims into the supplied 'message' parameter.
41*4b347fccSAndrew Lindesay */
42*4b347fccSAndrew Lindesay 
43*4b347fccSAndrew Lindesay /*static*/ status_t
ParseClaims(const BString & token,BMessage & message)44*4b347fccSAndrew Lindesay JwtTokenHelper::ParseClaims(const BString& token, BMessage& message)
45*4b347fccSAndrew Lindesay {
46*4b347fccSAndrew Lindesay 	int firstDot = token.FindFirst('.');
47*4b347fccSAndrew Lindesay 
48*4b347fccSAndrew Lindesay 	if (firstDot == B_ERROR)
49*4b347fccSAndrew Lindesay 		return B_BAD_VALUE;
50*4b347fccSAndrew Lindesay 
51*4b347fccSAndrew Lindesay 	// find the end of the first section by looking for the next dot.
52*4b347fccSAndrew Lindesay 
53*4b347fccSAndrew Lindesay 	int secondDot = token.FindFirst('.', firstDot + 1);
54*4b347fccSAndrew Lindesay 
55*4b347fccSAndrew Lindesay 	if (secondDot == B_ERROR)
56*4b347fccSAndrew Lindesay 		return B_BAD_VALUE;
57*4b347fccSAndrew Lindesay 
58*4b347fccSAndrew Lindesay 	BMemoryIO memoryIo(&(token.String())[firstDot + 1], (secondDot - firstDot) - 1);
59*4b347fccSAndrew Lindesay 	Base64DecodingDataIO base64DecodingIo(&memoryIo, '-', '_');
60*4b347fccSAndrew Lindesay 	BJsonMessageWriter writer(message);
61*4b347fccSAndrew Lindesay 	BJson::Parse(&base64DecodingIo, &writer);
62*4b347fccSAndrew Lindesay 
63*4b347fccSAndrew Lindesay 	return writer.ErrorStatus();
64*4b347fccSAndrew Lindesay }
65*4b347fccSAndrew Lindesay 
66*4b347fccSAndrew Lindesay 
67*4b347fccSAndrew Lindesay /*! Note this is base64 "url" standard that disallows "/" and "+" and instead
68*4b347fccSAndrew Lindesay     uses "-" and "_".
69*4b347fccSAndrew Lindesay */
70*4b347fccSAndrew Lindesay 
71*4b347fccSAndrew Lindesay /*static*/ bool
_IsBase64(char ch)72*4b347fccSAndrew Lindesay JwtTokenHelper::_IsBase64(char ch)
73*4b347fccSAndrew Lindesay {
74*4b347fccSAndrew Lindesay 	return isalnum(ch)
75*4b347fccSAndrew Lindesay 		|| '=' == ch
76*4b347fccSAndrew Lindesay 		|| '-' == ch
77*4b347fccSAndrew Lindesay 		|| '_' == ch;
78*4b347fccSAndrew Lindesay }
79