-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Cédric Foellmi <[email protected]>
- Loading branch information
1 parent
6f53634
commit 8ecebf5
Showing
4 changed files
with
121 additions
and
66 deletions.
There are no files selected for viewing
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
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 |
---|---|---|
@@ -1,64 +1,102 @@ | ||
import json | ||
import os | ||
|
||
import click | ||
import machineid | ||
import requests | ||
|
||
from arcsecond import Config | ||
from .utils import generate_password | ||
|
||
|
||
class KeygenClient(object): | ||
def __init__(self, state, do_try): | ||
self.__config = Config(state) | ||
def __init__(self, config, do_try, profile): | ||
self.__config = config | ||
self.__section_name = 'keygen:try' if do_try else 'keygen' | ||
self.__base_url = "https://api.keygen.sh/v1/accounts/arcsecond-io" | ||
self.__default_headers = { | ||
"Content-Type": "application/vnd.api+json", | ||
"Accept": "application/vnd.api+json" | ||
} | ||
self.__profile = profile | ||
|
||
def __config_save(self, **kwargs): | ||
kwargs.update(section=self.__section_name) | ||
self.__config.save(**kwargs) | ||
|
||
def get_user_id(self): | ||
self.__config.read_key('user', self.__section_name) | ||
def __config_get(self, key): | ||
return self.__config.read_key(key, self.__section_name) | ||
|
||
def create_user(self, arcsecond_profile): | ||
user_id = self.get_user_id() | ||
def __create_user(self): | ||
user_id = self.__config_get('user_id') | ||
if user_id is not None: | ||
return user_id | ||
return user_id, 'OK' | ||
|
||
email = self.__profile.get('email') | ||
password = generate_password() | ||
self.__config_save(password=password, email=email) | ||
|
||
res = requests.post( | ||
self.__base_url + "/users", | ||
headers=self.__default_headers, | ||
data=json.dumps({ | ||
"data": { | ||
"type": "users", | ||
"attributes": { | ||
"firstName": arcsecond_profile.get('first_name', 'Famous') or "Famous", | ||
"lastName": arcsecond_profile.get('last_name', 'Astronomer') or "Astronomer", | ||
"email": arcsecond_profile.get('email'), | ||
"password": None # passwordless user | ||
"firstName": self.__profile.get('first_name', 'Famous') or "Famous", | ||
"lastName": self.__profile.get('last_name', 'Astronomer') or "Astronomer", | ||
"email": email, | ||
"password": password | ||
} | ||
} | ||
}) | ||
) | ||
|
||
if res.status_code != 201: | ||
click.echo('We are unable to create user, yet we cannot find your user id.') | ||
click.echo('Please, contact [email protected] to fix the situation.') | ||
return | ||
user_id = res.json().get('data').get('id') | ||
self.__config_save(user=user_id, email=arcsecond_profile.get('email')) | ||
return user_id | ||
msg = 'We are unable to create user, yet we cannot find your user id.\n' | ||
msg += 'Please, contact [email protected] to fix the situation.' | ||
return None, msg | ||
|
||
data = res.json().get('data') | ||
user_id = data.get('id') | ||
self.__config_save(user_id=user_id) | ||
|
||
return user_id, 'OK' | ||
|
||
def _generate_user_token(self): | ||
email, password = self.__config_get('email'), self.__config_get('password') | ||
res = requests.post( | ||
self.__base_url + "/tokens", | ||
headers={"Accept": "application/vnd.api+json"}, | ||
auth=(email, password) | ||
) | ||
data = res.json().get('data') | ||
user_token = data.get('attributes').get('token') | ||
self.__config_save(user_token=user_token) | ||
return user_token, 'OK' | ||
|
||
def __create_license(self, user_id): | ||
license_key = self.__config_get('license_key') | ||
if license_key: | ||
return license_key, 'OK' | ||
|
||
user_token, msg = self._generate_user_token() | ||
res = requests.get( | ||
self.__base_url + "/licenses?limit=1", | ||
headers={ | ||
"Accept": "application/vnd.api+json", | ||
"Authorization": "Bearer " + user_token | ||
} | ||
) | ||
|
||
data = res.json().get('data') | ||
if len(data) == 1: | ||
license_id = data[0].get('id') | ||
license_key = data[0].get('attributes').get('key') | ||
self.__config_save(licence_id=license_id, license_key=license_key) | ||
return license_key, 'OK' | ||
|
||
def create_license(self): | ||
user_id = self.get_user_id() | ||
if user_id is not None: | ||
return None | ||
product_id = 'cf22a770-6252-44c2-b1ad-acd9dccad9ff' | ||
policy_id = '8cecf79e-35b4-40fb-848b-31b0c19455ba' | ||
headers = {**self.__default_headers} | ||
headers['Authorization'] = "Bearer " + product_id | ||
headers['Authorization'] = "Bearer " + user_token | ||
res = requests.post( | ||
self.__base_url + "/licenses", | ||
headers=headers, | ||
|
@@ -76,34 +114,37 @@ def create_license(self): | |
} | ||
}) | ||
) | ||
print(res.json()) | ||
|
||
def activate_license(license_key): | ||
machine_fingerprint = machineid.hashed_id('arcsecond') | ||
validation = requests.post( | ||
"https://api.keygen.sh/v1/accounts/{}/licenses/actions/validate-key".format( | ||
os.environ['KEYGEN_ACCOUNT_ID']), | ||
headers={ | ||
"Content-Type": "application/vnd.api+json", | ||
"Accept": "application/vnd.api+json" | ||
}, | ||
# TODO: deal with failure. | ||
data = res.json().get('data') | ||
license_id = data.get('id') | ||
license_key = data.get('attributes').get('key') | ||
self.__config_save(licence_id=license_id, license_key=license_key) | ||
|
||
return license_key, 'OK' | ||
|
||
def __activate_license(self, license_key): | ||
machine_fingerprint = machineid.hashed_id() | ||
res = requests.post( | ||
self.__base_url + "/licenses/actions/validate-key", | ||
headers=self.__default_headers, | ||
data=json.dumps({ | ||
"meta": { | ||
"scope": {"fingerprint": machine_fingerprint}, | ||
"key": license_key | ||
"key": license_key, | ||
"scope": { | ||
"fingerprint": machine_fingerprint | ||
} | ||
} | ||
}) | ||
).json() | ||
) | ||
|
||
validation = res.json() | ||
if "errors" in validation: | ||
errs = validation["errors"] | ||
|
||
return False, "license validation failed: {}".format( | ||
','.join(map(lambda e: "{} - {}".format(e["title"], e["detail"]).lower(), errs)) | ||
) | ||
|
||
# If the license is valid for the current machine, that means it has | ||
# already been activated. We can return early. | ||
if validation["meta"]["valid"]: | ||
return True, "license has already been activated on this machine" | ||
|
||
|
@@ -122,13 +163,11 @@ def activate_license(license_key): | |
|
||
# If we've gotten this far, then our license has not been activated yet, | ||
# so we should go ahead and activate the current machine. | ||
activation = requests.post( | ||
"https://api.keygen.sh/v1/accounts/{}/machines".format(os.environ['KEYGEN_ACCOUNT_ID']), | ||
headers={ | ||
"Authorization": "License {}".format(license_key), | ||
"Content-Type": "application/vnd.api+json", | ||
"Accept": "application/vnd.api+json" | ||
}, | ||
headers = {**self.__default_headers} | ||
headers['Authorization'] = "License " + license_key | ||
res = requests.post( | ||
self.__base_url + "/machines", | ||
headers=headers, | ||
data=json.dumps({ | ||
"data": { | ||
"type": "machines", | ||
|
@@ -142,16 +181,28 @@ def activate_license(license_key): | |
} | ||
} | ||
}) | ||
).json() | ||
) | ||
|
||
activation = res.json() | ||
# If we get back an error, our activation failed. | ||
if "errors" in activation: | ||
errs = activation["errors"] | ||
|
||
return False, "license activation failed: {}".format( | ||
','.join(map(lambda e: "{} - {}".format(e["title"], e["detail"]).lower(), errs)) | ||
) | ||
|
||
return True, "license activated" | ||
|
||
# Run from the command line: | ||
def setup_and_validate_license(self): | ||
user_id, msg = self.__create_user() | ||
if user_id is None: | ||
click.echo(msg) | ||
return | ||
|
||
license_key, msg = self.__create_license(user_id) | ||
if license_key is None: | ||
click.echo(msg) | ||
return | ||
|
||
status, msg = self.__activate_license(license_key) | ||
return status, msg |
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,7 @@ | ||
import secrets | ||
|
||
|
||
def generate_password(): | ||
# No '%' to avoid interpolation surprises | ||
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZ0123456789!@#$^&*(-_=+)' | ||
return ''.join(secrets.choice(chars) for i in range(16)) |
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 |
---|---|---|
|
@@ -2,15 +2,15 @@ | |
|
||
import click | ||
|
||
from arcsecond import Config, ArcsecondAPI | ||
from arcsecond.hosting import docker | ||
from arcsecond.hosting import keygen | ||
from .constants import BANNER, PREFIX | ||
from .checks import ( | ||
fetch_user_profile, | ||
is_arcsecond_api_reachable, | ||
is_user_logged_in, | ||
has_user_verified_email | ||
) | ||
from .constants import BANNER, PREFIX | ||
from .setup import setup_hosting_variables | ||
|
||
__version__ = '0.1.0 (Alpha) - Please, send feedback to [email protected]' | ||
|
@@ -31,13 +31,17 @@ def run_arcsecond(state, do_try=True, skip_setup=False): | |
if do_try is False and not has_user_verified_email(state): | ||
return | ||
|
||
# config = Config(state) | ||
klient = keygen.KeygenClient(state, do_try) | ||
profile = fetch_user_profile(state) | ||
klient.create_user(profile) | ||
klient.create_license() | ||
profile, error = ArcsecondAPI(state).fetch_full_profile() | ||
if error is not None: | ||
click.echo(str(error)) | ||
return | ||
|
||
return | ||
config = Config(state) | ||
klient = keygen.KeygenClient(config, do_try, profile) | ||
status, msg = klient.setup_and_validate_license() | ||
click.echo(PREFIX + msg) | ||
if status is False: | ||
return | ||
|
||
if not skip_setup: | ||
setup_hosting_variables(config, do_try=do_try) | ||
|