1
+ <?php
2
+ require_once 'components/Jwt.php ' ;
3
+ require_once 'components/Key.php ' ;
4
+
5
+ class Session {
6
+ public function __construct (
7
+ public string $ sessionName ,
8
+ ) {}
9
+
10
+ public function get () {
11
+ if (!isset ($ _COOKIE [$ this ->sessionName ]))
12
+ throw new Exception ("Access token cookie not set " );
13
+
14
+ try {
15
+ $ session = Firebase \JWT \JWT ::decode ($ _COOKIE [$ this ->sessionName ], new Firebase \JWT \Key ('yWvati2Z94ZV6XFaSwC7gqdsabtTYHqMnzWB7o58AvCXHkheS8ANfHLKTTwXE9cXHg7GH2bSb9q95Lo2He9XDWtqDBwJzvKFbX8ymeLPkhFQkJxF8GDbmpRUfeXctiLi ' , 'HS256 ' ));
16
+ }
17
+ catch (Exception ) {
18
+ setcookie ('accessToken ' , '' , 0 , '/ ' ); // delete cookie on browser
19
+ throw new Exception ("Failed to decode access token " );
20
+ }
21
+
22
+ return new Account (id: (int ) $ session ->id , auth: (bool ) $ session ->auth , mfa: $ session ->mfa , email: $ session ->email );
23
+ }
24
+ public function set ($ sessionValue ) {
25
+ setcookie ($ this ->sessionName , $ sessionValue , time ()+86400 , "/ " );
26
+ return ;
27
+ }
28
+ public function start ($ payload ) {
29
+ $ encoded = Firebase \JWT \JWT ::encode ($ payload , 'yWvati2Z94ZV6XFaSwC7gqdsabtTYHqMnzWB7o58AvCXHkheS8ANfHLKTTwXE9cXHg7GH2bSb9q95Lo2He9XDWtqDBwJzvKFbX8ymeLPkhFQkJxF8GDbmpRUfeXctiLi ' , 'HS256 ' );
30
+ $ this ->set ($ encoded );
31
+ }
32
+ }
33
+
34
+ class Account {
35
+ public function __construct (
36
+ public ?int $ id = null ,
37
+ public ?bool $ auth = null ,
38
+ public ?string $ mfa = null ,
39
+ public ?string $ email = null ,
40
+ ) {}
41
+
42
+ public function isAuthenticated () {
43
+ return $ this ->auth ;
44
+ }
45
+
46
+ public function register ($ password ) {
47
+ if (empty ($ this ->email ))
48
+ throw new Exception ("Email has not been specified " );
49
+
50
+ if (empty ($ password ))
51
+ throw new Exception ("Password has not been specified " );
52
+
53
+ $ db = new Database ("localhost " , "root " , "" , "jwt-webauthn-php " );
54
+ $ query = $ db ->query ("SELECT 1 FROM `accounts` WHERE `email` = ? " , [$ this ->email ]);
55
+ if ($ query ->num_rows >= 1 ) {
56
+ throw new Exception ("Email already taken! " );
57
+ }
58
+
59
+ $ passHashed = password_hash ($ password , PASSWORD_BCRYPT );
60
+
61
+ $ query = $ db ->query ("INSERT INTO `accounts` (`email`, `password`) VALUES (?, ?) " , [$ this ->email , $ passHashed ]);
62
+ if ($ query ->affected_rows > 0 ) {
63
+ $ session = new Session ("accessToken " );
64
+ $ session ->start (array ("id " => (int ) $ query ->insert_id , "auth " => true , "mfa " => null , "email " => $ this ->email ));
65
+ return true ;
66
+ }
67
+ else {
68
+ throw new Exception ("Failed to register account " );
69
+ }
70
+ }
71
+
72
+ public function login ($ password ) {
73
+ if (empty ($ this ->email ))
74
+ throw new Exception ("Email has not been specified " );
75
+
76
+ if (empty ($ password ))
77
+ throw new Exception ("Password has not been specified " );
78
+
79
+ $ db = new Database ("localhost " , "root " , "" , "jwt-webauthn-php " );
80
+ $ query = $ db ->query ("SELECT * FROM `accounts` WHERE `email` = ? " , [$ this ->email ]);
81
+ if ($ query ->num_rows < 1 ) {
82
+ throw new Exception ("Email not found! " );
83
+ }
84
+
85
+ while ($ row = mysqli_fetch_array ($ query ->result )) {
86
+ $ id = $ row ['id ' ];
87
+ $ passHashed = $ row ['password ' ];
88
+ $ securityKey = $ row ['securityKey ' ];
89
+ }
90
+
91
+ if (password_verify ($ password , $ passHashed )) {
92
+ $ session = new Session ("accessToken " );
93
+ $ session ->start (array ("id " => (int ) $ id , "auth " => !$ securityKey , "mfa " => $ securityKey ? "webauthn " : null , "email " => $ this ->email ));
94
+ }
95
+ else {
96
+ throw new Exception ("Password is invalid " );
97
+ }
98
+
99
+ if ($ securityKey )
100
+ throw new Exception ("Security key required. " );
101
+
102
+ return true ;
103
+ }
104
+ }
105
+
106
+ class Database {
107
+ private $ connection ;
108
+
109
+ public function __construct ($ databaseHost , $ databaseUsername , $ databasePassword , $ databaseName ) {
110
+ $ this ->connection = new mysqli ($ databaseHost , $ databaseUsername , $ databasePassword , $ databaseName );
111
+
112
+ if (!$ this ->connection )
113
+ throw new Exception ($ this ->connection ->connect_error );
114
+ }
115
+
116
+ public function __destruct () {
117
+ $ this ->connection ->close ();
118
+ }
119
+
120
+ public function query ($ query , $ args = [], $ types = null ) {
121
+ if (is_null ($ types ) && !empty ($ args ))
122
+ $ types = str_repeat ('s ' , count ($ args )); // unless otherwise specified, set type to string
123
+
124
+ $ stmt = $ this ->connection ->prepare ($ query );
125
+
126
+ if (!$ stmt )
127
+ throw new Exception ($ this ->connection ->error );
128
+
129
+ if (str_contains ($ query , "? " ))
130
+ $ stmt ->bind_param ($ types , ...$ args );
131
+
132
+ $ stmt ->execute ();
133
+
134
+ $ query = new \stdClass ();
135
+ $ query ->result = $ stmt ->get_result ();
136
+ $ query ->num_rows = $ query ->result ->num_rows ;
137
+ $ query ->affected_rows = $ stmt ->affected_rows ;
138
+ $ query ->insert_id = $ stmt ->insert_id ;
139
+
140
+ $ stmt ->close ();
141
+
142
+ return $ query ;
143
+ }
144
+ }
145
+
146
+ class Response {
147
+ public function __construct (
148
+ public ?int $ status = null ,
149
+ public ?array $ data = null ,
150
+ public ?string $ error = null ,
151
+ public ?string $ message = null ,
152
+ public ?string $ env = null ,
153
+ public ?string $ log = null ,
154
+ ) {}
155
+
156
+ public function send () {
157
+ header ("Content-type: application/json " );
158
+ die (json_encode (array ("status " => (int ) $ this ->status , "data " => $ this ->data , "error " => $ this ->error , "message " => $ this ->message , "env " => $ this ->env , "log " => $ this ->log )));
159
+ }
160
+ }
0 commit comments