Skip to content

Commit

Permalink
feat: allow users to specify an X-Client-Token (hidden menu)
Browse files Browse the repository at this point in the history
Workaround for go-vikunja#67
  • Loading branch information
denysvitali committed Apr 5, 2024
1 parent 64fa13c commit 6052d5c
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 111 deletions.
11 changes: 10 additions & 1 deletion lib/api/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,34 @@ class Client {
final JsonEncoder _encoder = new JsonEncoder();
String _token = '';
String _base = '';
String _xClientToken = '';
bool authenticated = false;
bool ignoreCertificates = false;
bool showSnackBar = true;

String get base => _base;
String get token => _token;
String get xClientToken => _xClientToken;

String? post_body;

@override
bool operator ==(Object otherClient) {
if (otherClient is! Client) return false;
return otherClient._token == _token;
return otherClient._token == _token &&
otherClient._xClientToken == _xClientToken;
}

Client(
this.global_scaffold_key, {
String? token,
String? xClientToken,
String? base,
bool authenticated = false,
}) {
configure(
token: token,
xClientToken: xClientToken,
base: base,
authenticated: authenticated,
);
Expand Down Expand Up @@ -76,6 +81,7 @@ class Client {
'Authorization': _token != '' ? 'Bearer $_token' : '',
'Content-Type': 'application/json',
'User-Agent': 'Vikunja Mobile App',
'X-Client-Token': _xClientToken
};

get headers => _headers;
Expand All @@ -87,8 +93,10 @@ class Client {
String? token,
String? base,
bool? authenticated,
String? xClientToken,
}) {
if (token != null) _token = token;
if (xClientToken != null) _xClientToken = xClientToken;
if (base != null) {
base = base.replaceAll(" ", "");
if (base.endsWith("/")) base = base.substring(0, base.length - 1);
Expand All @@ -98,6 +106,7 @@ class Client {
}

void reset() {
_token = _base = _xClientToken = '';
authenticated = false;
}

Expand Down
11 changes: 8 additions & 3 deletions lib/api/user_implementation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ class UserAPIService extends APIService implements UserService {
UserAPIService(Client client) : super(client);

@override
Future<UserTokenPair> login(String username, password,
{bool rememberMe = false, String? totp}) async {
Future<UserTokenPair> login(
String username,
password, {
bool rememberMe = false,
String? totp,
String? xClientToken,
}) async {
var body = {
'long_token': rememberMe,
'password': password,
Expand All @@ -26,7 +31,7 @@ class UserAPIService extends APIService implements UserService {
error: response != null ? response.body["code"] : 0,
errorString:
response != null ? response.body["message"] : "Login error"));
client.configure(token: token);
client.configure(token: token, xClientToken: xClientToken);
return UserAPIService(client)
.getCurrentUser()
.then((user) => UserTokenPair(user, token));
Expand Down
1 change: 1 addition & 0 deletions lib/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const ErrorCodeOtpRequired = 1017;
29 changes: 26 additions & 3 deletions lib/global.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
initialDelay: Duration(seconds: 15),
inputData: {
"client_token": client.token,
"client_base": client.base
"client_base": client.base,
"x_client_token": client.xClientToken,
});
}

Expand Down Expand Up @@ -132,7 +133,12 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
});
}

void changeUser(User newUser, {String? token, String? base}) async {
void changeUser(
User newUser, {
String? token,
String? base,
String? xClientToken,
}) async {
setState(() {
_loading = true;
});
Expand All @@ -148,6 +154,16 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
// Write new base to secure storage
await _storage.write(key: "${newUser.id.toString()}_base", value: base);
}

if (xClientToken == null) {
xClientToken =
await _storage.read(key: "${newUser.id.toString()}_x_client_token");
} else {
// Write new xClientToken to secure storage
await _storage.write(
key: "${newUser.id.toString()}_x_client_token", value: xClientToken);
}

// Set current user in storage
await _storage.write(key: 'currentUser', value: newUser.id.toString());
client.configure(token: token, base: base, authenticated: true);
Expand Down Expand Up @@ -185,13 +201,20 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
}
var token = await _storage.read(key: currentUser);
var base = await _storage.read(key: '${currentUser}_base');
var xClientToken =
await _storage.read(key: '${currentUser}_x_client_token');
if (token == null || base == null) {
setState(() {
_loading = false;
});
return;
}
client.configure(token: token, base: base, authenticated: true);
client.configure(
token: token,
base: base,
authenticated: true,
xClientToken: xClientToken,
);
User loadedCurrentUser;
try {
loadedCurrentUser = await UserAPIService(client).getCurrentUser();
Expand Down
33 changes: 18 additions & 15 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,14 @@ class IgnoreCertHttpOverrides extends HttpOverrides {

@pragma('vm:entry-point')
void callbackDispatcher() {
if (kIsWeb) {
return;
}
Workmanager().executeTask((task, inputData) async {
print(
"Native called background task: $task"); //simpleTask will be emitted here.
if (task == "update-tasks" && inputData != null) {
Client client = Client(null,
token: inputData["client_token"],
base: inputData["client_base"],
xClientToken: inputData["x_client_token"],
authenticated: true);
tz.initializeTimeZones();

Expand All @@ -70,13 +68,19 @@ void callbackDispatcher() {
return Future.value(true);
}
var token = await _storage.read(key: currentUser);

var base = await _storage.read(key: '${currentUser}_base');
var xClientToken =
await _storage.read(key: '${currentUser}_x_client_token');
if (token == null || base == null) {
return Future.value(true);
}
Client client = Client(null);
client.configure(token: token, base: base, authenticated: true);
client.configure(
token: token,
base: base,
xClientToken: xClientToken,
authenticated: true,
);
// load new token from server to avoid expiration
String? newToken = await UserAPIService(client).getToken();
if (newToken != null) {
Expand Down Expand Up @@ -114,16 +118,15 @@ void main() async {
print("Failed to initialize workmanager: $e");
}
runApp(VikunjaGlobal(
child: new VikunjaApp(
home: HomePage(),
key: UniqueKey(),
navkey: globalNavigatorKey,
),
login: new VikunjaApp(
home: LoginPage(),
key: UniqueKey(),
),
));
child: new VikunjaApp(
home: HomePage(),
key: UniqueKey(),
navkey: globalNavigatorKey,
),
login: new VikunjaApp(
home: LoginPage(),
key: UniqueKey(),
)));
}

final ValueNotifier<bool> updateTheme = ValueNotifier(false);
Expand Down
Loading

0 comments on commit 6052d5c

Please sign in to comment.