1
1
package de .malkusch .niu ;
2
2
3
- import static java .util .Objects .requireNonNull ;
4
3
5
4
import java .io .IOException ;
5
+ import java .math .BigInteger ;
6
+ import java .security .MessageDigest ;
7
+ import java .security .NoSuchAlgorithmException ;
6
8
import java .time .Duration ;
7
9
import java .time .Instant ;
8
10
9
- import com .auth0 .jwt .JWT ;
11
+ import static java .nio .charset .StandardCharsets .UTF_8 ;
12
+ import static java .util .Objects .requireNonNull ;
10
13
11
14
final class Authentication {
12
15
13
16
private final String account ;
14
17
private final String password ;
15
18
private final String countryCode ;
16
19
private final Client client ;
20
+ private final static String APP_ID = "niu_8xt1afu6" ;
17
21
18
22
public Authentication (String account , String password , String countryCode , Duration expirationWindow , Client client )
19
23
throws IOException {
20
24
21
25
this .account = assertNotEmpty (account , "account must not be empty" );
22
- this .password = assertNotEmpty (password , "password must not be empty" );
26
+ this .password = hashedPassword ( assertNotEmpty (password , "password must not be empty" ) );
23
27
this .countryCode = assertNotEmpty (countryCode , "countryCode must not be empty" );
24
28
this .expirationWindow = requireNonNull (expirationWindow );
25
29
this .client = requireNonNull (client );
26
30
27
31
refreshToken ();
28
32
}
29
33
34
+ private static String hashedPassword (String password ) {
35
+ try {
36
+ var md5 = MessageDigest .getInstance ("MD5" );
37
+ md5 .update (UTF_8 .encode (password ));
38
+ return String .format ("%032x" , new BigInteger (1 , md5 .digest ()));
39
+
40
+ } catch (NoSuchAlgorithmException e ) {
41
+ throw new IllegalStateException (e );
42
+ }
43
+ }
44
+
30
45
private static String assertNotEmpty (String value , String errorMessage ) {
31
46
requireNonNull (value );
32
47
if (value .isEmpty ()) {
@@ -51,29 +66,36 @@ public Token token() throws IOException {
51
66
}
52
67
53
68
private final Duration expirationWindow ;
54
- private static final String LOGIN_URI = "https://account-fk.niu.com/appv2/login " ;
69
+ private static final String LOGIN_URI = "https://account-fk.niu.com/v3/api/oauth2/token " ;
55
70
private static Duration EXPIRES_AT_FALLBACK = Duration .ofHours (1 );
56
71
57
72
private void refreshToken () throws IOException {
58
73
74
+ // Todo Use refresh token
75
+
59
76
record Response (Data data , String desc , int status ) {
60
- record Data (String token ) {
77
+ record Data (Token token ) {
78
+ record Token (String access_token , Instant token_expires_in ) {
79
+ }
61
80
}
62
81
}
63
- var response = client .post (Response .class , LOGIN_URI , new Field ("countryCode" , countryCode ),
64
- new Field ("account" , account ), new Field ("password" , password ));
82
+ var response = client .post (Response .class , LOGIN_URI ,
83
+ new Field ("countryCode" , countryCode ),
84
+ new Field ("app_id" , APP_ID ),
85
+ new Field ("grant_type" , "password" ),
86
+ new Field ("account" , account ),
87
+ new Field ("password" , password ));
65
88
66
89
if (response .status != 0 ) {
67
90
throw new IOException (String .format ("Can't authenticate: [%d] %s" , response .status , response .desc ));
68
91
}
69
92
70
- var token = response .data .token ;
93
+ var token = response .data .token . access_token ;
71
94
72
95
Instant expiresAt ;
73
96
try {
74
- var jwt = JWT .decode (token );
75
97
var now = Instant .now ();
76
- expiresAt = jwt . getExpiresAtAsInstant () ;
98
+ expiresAt = response . data . token . token_expires_in ;
77
99
if (expiresAt == null ) {
78
100
expiresAt = now .plus (EXPIRES_AT_FALLBACK );
79
101
}
0 commit comments