-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract TiliadoActivationLocal from ActivationManager
It can be used in the App runner process. Issue: #404 Signed-off-by: Jiří Janoušek <[email protected]>
- Loading branch information
1 parent
d543bef
commit d7103ef
Showing
2 changed files
with
239 additions
and
175 deletions.
There are no files selected for viewing
221 changes: 221 additions & 0 deletions
221
src/nuvolakit-runner/tiliado/TiliadoActivationLocal.vala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
/* | ||
* Copyright 2017-2018 Jiří Janoušek <[email protected]> | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* 1. Redistributions of source code must retain the above copyright notice, this | ||
* list of conditions and the following disclaimer. | ||
* 2. Redistributions in binary form must reproduce the above copyright notice, | ||
* this list of conditions and the following disclaimer in the documentation | ||
* and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
|
||
namespace Nuvola { | ||
|
||
public class TiliadoActivationLocal : GLib.Object, TiliadoActivation { | ||
private const string TILIADO_ACCOUNT_TOKEN_TYPE = "tiliado.account2.token_type"; | ||
private const string TILIADO_ACCOUNT_ACCESS_TOKEN = "tiliado.account2.access_token"; | ||
private const string TILIADO_ACCOUNT_REFRESH_TOKEN = "tiliado.account2.refresh_token"; | ||
private const string TILIADO_ACCOUNT_SCOPE = "tiliado.account2.scope"; | ||
private const string TILIADO_ACCOUNT_MEMBERSHIP = "tiliado.account2.membership"; | ||
private const string TILIADO_ACCOUNT_USER = "tiliado.account2.user"; | ||
private const string TILIADO_ACCOUNT_EXPIRES = "tiliado.account2.expires"; | ||
private const string TILIADO_ACCOUNT_SIGNATURE = "tiliado.account2.signature"; | ||
|
||
public TiliadoApi2 tiliado {get; construct;} | ||
public Config config {get; construct;} | ||
private TiliadoApi2.User? cached_user = null; | ||
|
||
public TiliadoActivationLocal(TiliadoApi2 tiliado, Config config) { | ||
GLib.Object(tiliado: tiliado, config: config); | ||
} | ||
|
||
construct { | ||
tiliado.notify["token"].connect_after(on_api_token_changed); | ||
tiliado.notify["user"].connect_after(on_api_user_changed); | ||
tiliado.device_code_grant_started.connect(on_device_code_grant_started); | ||
tiliado.device_code_grant_error.connect(on_device_code_grant_error); | ||
tiliado.device_code_grant_cancelled.connect(on_device_code_grant_cancelled); | ||
tiliado.device_code_grant_finished.connect(on_device_code_grant_finished); | ||
load_cached_data(); | ||
} | ||
|
||
~TiliadoActivationLocal() { | ||
tiliado.notify["token"].disconnect(on_api_token_changed); | ||
tiliado.notify["user"].disconnect(on_api_user_changed); | ||
tiliado.device_code_grant_started.disconnect(on_device_code_grant_started); | ||
tiliado.device_code_grant_error.disconnect(on_device_code_grant_error); | ||
tiliado.device_code_grant_cancelled.disconnect(on_device_code_grant_cancelled); | ||
tiliado.device_code_grant_finished.disconnect(on_device_code_grant_finished); | ||
} | ||
|
||
public TiliadoApi2.User? get_user_info() { | ||
TiliadoApi2.User? current_user = tiliado.user; | ||
return current_user != null && current_user.is_valid() ? current_user : cached_user; | ||
} | ||
|
||
public void update_user_info() { | ||
tiliado.fetch_current_user.begin(on_update_current_user_done); | ||
} | ||
|
||
public TiliadoApi2.User? update_user_info_sync() { | ||
if (tiliado.token == null) { | ||
return null; | ||
} else { | ||
return update_user_info_sync_internal(); | ||
} | ||
} | ||
|
||
public void start_activation() { | ||
tiliado.start_device_code_grant(TILIADO_OAUTH2_DEVICE_CODE_ENDPOINT); | ||
} | ||
|
||
public void cancel_activation() { | ||
tiliado.cancel_device_code_grant(); | ||
} | ||
|
||
public void drop_activation() { | ||
tiliado.drop_token(); | ||
update_user_info(); | ||
} | ||
|
||
private void on_device_code_grant_started(string url) { | ||
activation_started(url); | ||
} | ||
|
||
private void on_device_code_grant_error(string code, string? message) { | ||
string detail; | ||
switch (code) { | ||
case "parse_error": | ||
case "response_error": | ||
detail = "The server returned a malformed response."; | ||
break; | ||
case "invalid_client": | ||
case "unauthorized_client": | ||
detail = "This build of %s is not authorized to use the Tiliado API.".printf(Nuvola.get_app_name()); | ||
break; | ||
case "access_denied": | ||
detail = "The authorization request has been dismissed. Please try again."; | ||
break; | ||
case "expired_token": | ||
detail = "The authorization request has expired. Please try again."; | ||
break; | ||
default: | ||
detail = "%s has sent an invalid request.".printf(Nuvola.get_app_name()); | ||
break; | ||
} | ||
activation_failed(detail); | ||
} | ||
|
||
private void on_device_code_grant_cancelled() { | ||
activation_cancelled(); | ||
} | ||
|
||
private void on_device_code_grant_finished(Oauth2Token token) { | ||
tiliado.fetch_current_user.begin(on_get_current_user_for_activation_done); | ||
} | ||
|
||
private void on_get_current_user_for_activation_done(GLib.Object? o, AsyncResult res) { | ||
try { | ||
TiliadoApi2.User? user = tiliado.fetch_current_user.end(res); | ||
user = user != null && user.is_valid() ? user : null; | ||
activation_finished(user); | ||
} | ||
catch (Oauth2Error e) { | ||
string err = "Failed to fetch user's details. " + e.message; | ||
activation_failed(err); | ||
} | ||
cache_user(tiliado.user); | ||
} | ||
|
||
private void on_update_current_user_done(GLib.Object? o, AsyncResult res) { | ||
try { | ||
TiliadoApi2.User? user = tiliado.fetch_current_user.end(res); | ||
user = user != null && user.is_valid() ? user : null; | ||
user_info_updated(user); | ||
} | ||
catch (Oauth2Error e) { | ||
user_info_updated(null); | ||
} | ||
} | ||
|
||
private void load_cached_data() { | ||
if (config.has_key(TILIADO_ACCOUNT_ACCESS_TOKEN)) { | ||
tiliado.token = new Oauth2Token( | ||
config.get_string(TILIADO_ACCOUNT_ACCESS_TOKEN), | ||
config.get_string(TILIADO_ACCOUNT_REFRESH_TOKEN), | ||
config.get_string(TILIADO_ACCOUNT_TOKEN_TYPE), | ||
config.get_string(TILIADO_ACCOUNT_SCOPE)); | ||
|
||
string? signature = config.get_string(TILIADO_ACCOUNT_SIGNATURE); | ||
if (signature != null) { | ||
int64 expires = config.get_int64(TILIADO_ACCOUNT_EXPIRES); | ||
string? user_name = config.get_string(TILIADO_ACCOUNT_USER); | ||
uint membership = (uint) config.get_int64(TILIADO_ACCOUNT_MEMBERSHIP); | ||
if (tiliado.hmac_sha1_verify_string(concat_tiliado_user_info(user_name, membership, expires), signature)) { | ||
// FIXME: check expiration | ||
var user = new TiliadoApi2.User(0, null, user_name, true, true, new int[] {}); | ||
user.membership = membership; | ||
cached_user = user; | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void cache_user(TiliadoApi2.User? user) { | ||
cached_user = null; | ||
if (user != null && user.is_valid()) { | ||
int64 expires = new DateTime.now_utc().add_weeks(5).to_unix(); | ||
config.set_string(TILIADO_ACCOUNT_USER, user.name); | ||
config.set_int64(TILIADO_ACCOUNT_MEMBERSHIP, (int64) user.membership); | ||
config.set_int64(TILIADO_ACCOUNT_EXPIRES, expires); | ||
string signature = tiliado.hmac_sha1_for_string( | ||
concat_tiliado_user_info(user.name, user.membership, expires)); | ||
config.set_string(TILIADO_ACCOUNT_SIGNATURE, signature); | ||
} else { | ||
config.unset(TILIADO_ACCOUNT_USER); | ||
config.unset(TILIADO_ACCOUNT_MEMBERSHIP); | ||
config.unset(TILIADO_ACCOUNT_EXPIRES); | ||
config.unset(TILIADO_ACCOUNT_SIGNATURE); | ||
} | ||
} | ||
|
||
private inline string concat_tiliado_user_info(string name, uint membership_rank, int64 expires) { | ||
return "%s:%u:%s".printf(name, membership_rank, expires.to_string()); | ||
} | ||
|
||
private void on_api_token_changed(GLib.Object o, ParamSpec p) { | ||
Oauth2Token token = tiliado.token; | ||
if (token != null) { | ||
config.set_value(TILIADO_ACCOUNT_TOKEN_TYPE, token.token_type); | ||
config.set_value(TILIADO_ACCOUNT_ACCESS_TOKEN, token.access_token); | ||
config.set_value(TILIADO_ACCOUNT_REFRESH_TOKEN, token.refresh_token); | ||
config.set_value(TILIADO_ACCOUNT_SCOPE, token.scope); | ||
} else { | ||
config.unset(TILIADO_ACCOUNT_TOKEN_TYPE); | ||
config.unset(TILIADO_ACCOUNT_ACCESS_TOKEN); | ||
config.unset(TILIADO_ACCOUNT_REFRESH_TOKEN); | ||
config.unset(TILIADO_ACCOUNT_SCOPE); | ||
} | ||
} | ||
|
||
private void on_api_user_changed(GLib.Object o, ParamSpec p) { | ||
TiliadoApi2.User user = tiliado.user; | ||
cache_user(user); | ||
user_info_updated(user); | ||
} | ||
} | ||
|
||
} // namespace Nuvola |
Oops, something went wrong.