@@ -3,79 +3,100 @@ import { z } from 'zod';
3
3
import { Storage } from '../../storage/index.js' ;
4
4
5
5
/**
6
- * User object stored in the storage
6
+ * Interface defining the properties of a User object stored in storage.
7
7
*/
8
8
export interface User {
9
+ /** The username of the user */
9
10
login : string ;
11
+ /** The hashed password of the user */
10
12
hashedPassword : string ;
13
+ /** The optional JSON Web Token of the user */
11
14
jwt ?: string ;
12
15
}
13
16
14
17
/**
15
- * User creation API input validation schema
18
+ * Validation schema for user creation API input.
19
+ * It validates that the input contains a nonempty `login` and `password`.
16
20
*/
17
21
export const UserInputSchema = z . object ( {
18
- login : z . string ( ) ,
19
- password : z . string ( ) ,
22
+ login : z . string ( ) . nonempty ( ) ,
23
+ password : z . string ( ) . nonempty ( ) ,
20
24
} ) ;
21
25
22
26
/**
23
- * Users database initialization options type
27
+ * Type definition for User registration input,
28
+ * inferred from UserInputSchema.
29
+ */
30
+ export type UserInputType = z . infer < typeof UserInputSchema > ;
31
+
32
+ /**
33
+ * Interface defining the properties of UsersDb initialization options.
24
34
*/
25
35
export interface UsersDbOptions {
26
36
/** Instance of storage used for persisting the state of the API server */
27
37
storage : Storage ;
28
38
/** Prefix used for the storage key to avoid potential key collisions */
29
39
prefix : string ;
30
- /** Passwords hashing salt */
40
+ /** Salt used for hashing passwords */
31
41
salt : string ;
32
42
}
33
43
34
44
export class UsersDb {
35
45
/** Storage instance for persisting the state of the API server */
36
- private storage : Storage ;
46
+ storage : Storage ;
37
47
/** Specific key prefix for the storage key to avoid potential key collisions */
38
- private prefix : string ;
39
- /** Passwords hashing salt */
48
+ prefix : string ;
49
+ /** Salt used for hashing passwords */
40
50
salt : string ;
41
51
42
52
/**
43
53
* Creates an instance of UsersDb.
54
+ * Initializes an instance of UsersDb with given options.
44
55
*
45
56
* @param {UsersDbOptions } options
46
57
* @memberof NodeApiServer
47
58
*/
48
59
constructor ( options : UsersDbOptions ) {
49
60
const { storage, prefix, salt } = options ;
50
61
51
- // @todo Validate NodeApiServerOptions
62
+ // TODO Validate NodeApiServerOptions
52
63
53
64
this . prefix = `${ prefix } _api_users_` ;
54
65
this . storage = storage ;
55
66
this . salt = salt ;
56
67
}
57
68
69
+ /**
70
+ * Hashes the given password with the given salt.
71
+ *
72
+ * @static
73
+ * @param {string } password The password to be hashed
74
+ * @param {string } salt The salt to be used for hashing
75
+ * @returns {string } The hashed password
76
+ * @memberof UsersDb
77
+ */
58
78
static hashPassword ( password : string , salt : string ) : string {
59
79
return keccak256 ( `${ password } ${ salt } ` as Hex ) ;
60
80
}
61
81
62
82
/**
63
- * Returns prefixed login key
83
+ * Generates a prefixed login key
64
84
*
65
85
* @private
66
- * @param {string } login
67
- * @returns {string }
86
+ * @param {string } login The login for which the key is generated
87
+ * @returns {string } The prefixed login key
68
88
* @memberof UsersDb
69
89
*/
70
90
private loginKey ( login : string ) : string {
71
91
return `${ this . prefix } ${ login } ` ;
72
92
}
73
93
74
94
/**
75
- * Returns the user from storage
95
+ * Retrieves the user with the given login from storage.
76
96
*
77
- * @param {string } login
78
- * @returns {Promise<User> }
97
+ * @param {string } login The login of the user to be retrieved
98
+ * @returns {Promise<User> } The User object associated with the given login
99
+ * @throws Will throw an error if the user is not found
79
100
* @memberof UsersDb
80
101
*/
81
102
async get ( login : string ) : Promise < User > {
@@ -89,30 +110,48 @@ export class UsersDb {
89
110
}
90
111
91
112
/**
92
- * Creates a new user record in the storage
113
+ * Adds a new user to the storage.
93
114
*
94
- * @param {string } login
95
- * @param {string } password
115
+ * @param {string } login The login of the user to be added
116
+ * @param {string } password The password of the user to be added
96
117
* @returns {Promise<void> }
118
+ * @throws Will throw an error if a user with the same login already exists
97
119
* @memberof UsersDb
98
120
*/
99
121
async add ( login : string , password : string ) : Promise < void > {
100
122
const knownUser = await this . storage . get < User > ( this . loginKey ( login ) ) ;
101
123
124
+ // Check if the user already exists
102
125
if ( knownUser ) {
103
126
throw new Error ( `User ${ login } already exists` ) ;
104
127
}
105
128
129
+ // Save the user into the storage
106
130
await this . storage . set < User > ( this . loginKey ( login ) , {
107
131
login,
108
132
hashedPassword : UsersDb . hashPassword ( password , this . salt ) ,
109
133
} ) ;
110
134
}
111
135
136
+ /**
137
+ * Updates the record of the user in the storage
138
+ *
139
+ * @param {User } user The user object
140
+ * @returns {Promise<void> }
141
+ * @memberof UsersDb
142
+ */
112
143
async set ( user : User ) : Promise < void > {
113
144
await this . storage . set < User > ( this . loginKey ( user . login ) , user ) ;
114
145
}
115
146
147
+ /**
148
+ * Deletes the user from storage
149
+ *
150
+ * @param {string } login The user login name
151
+ * @returns {Promise<void> }
152
+ * @throws Will throw an error if not possible to delete the user
153
+ * @memberof UsersDb
154
+ */
116
155
async delete ( login : string ) : Promise < void > {
117
156
const deleted = await this . storage . delete ( this . loginKey ( login ) ) ;
118
157
0 commit comments