Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AccountKey to Accounts #92

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions migrations/V001.030__account_key.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Template migration.
*/

DROP TABLE IF EXISTS account_key_version;
DROP TABLE IF EXISTS account_key;

CREATE TABLE account_key (
id BIGINT NOT NULL PRIMARY KEY DEFAULT nextval('id_seq'),

created_at TIMESTAMP WITH TIME ZONE NOT NULL,
created_by BIGINT NOT NULL REFERENCES account,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_by BIGINT NOT NULL REFERENCES account,

account_id BIGINT NOT NULL REFERENCES account,
comment TEXT,
public_key TEXT NOT NULL,
key_type VARCHAR(50) NOT NULL
);
GRANT ALL ON account_key TO "p2k16-web";

CREATE TABLE account_key_version
(
transaction_id BIGINT NOT NULL REFERENCES transaction,
end_transaction_id BIGINT REFERENCES transaction,
operation_type INT NOT NULL,

id BIGINT NOT NULL,

created_at TIMESTAMP WITH TIME ZONE NOT NULL,
created_by BIGINT NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_by BIGINT NOT NULL,

account_id BIGINT,
comment TEXT,
public_key TEXT,
key_type VARCHAR(50)
);
GRANT INSERT, UPDATE ON account_key_version TO "p2k16-web";
GRANT ALL ON account_key_version TO "p2k16-web";

50 changes: 50 additions & 0 deletions web/src/p2k16/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,56 @@ def __init__(self, tool: ToolDescription, account: Account, started: DateTime):
def find_by_tool(_tool) -> Optional['ToolCheckout']:
return ToolCheckout.query.filter(ToolCheckout.tool_description_id == _tool.id).one_or_none()

# Also specified in the core_blueprint.py
class AccountKeyType(enum.Enum):
SSH = 1
WIREGUARD = 2


class AccountKey(DefaultMixin, db.Model):
__tablename = 'account_key'
__versioned__ = {}

account_id = Column("account_id", Integer, ForeignKey('account.id'), nullable=False)
comment = Column("comment", String(200))
public_key = Column("public_key", String(10000), nullable=False)
_key_type = Column("key_type", String(50), nullable=False)

account = relationship("Account", foreign_keys=[account_id])

def __init__(self, account: Account, comment: str, public_key: str,
key_type: AccountKeyType):
super().__init__()
self.account_id = account.id
self.comment = comment
self.public_key = public_key
self._key_type = key_type.name

def __repr__(self):
return '<AccountKey:%s, account=%s, key_type=%s, comment=%s>' % (self.id, self.account_id, self._key_type, self.comment)


@hybrid_property
def key_type(self) -> AccountKeyType:
return AccountKeyType[self._key_type]

@staticmethod
def find_by_id(_id) -> Optional["AccountKey"]:
return AccountKey.query.filter(AccountKey.id == _id).one_or_none()

@staticmethod
def get_by_id(_id) -> "AccountKey":
return AccountKey.query.filter(AccountKey.id == _id).one()

@staticmethod
def delete_by_id(_id):
c = AccountKey.get_by_id(_id)
db.session.delete(c)
db.session.flush()

@staticmethod
def find_by_account(_account) -> List["AccountKey"]:
return AccountKey.query.filter(AccountKey.account_id == _account.id).all()

from sqlalchemy import event

Expand Down
73 changes: 72 additions & 1 deletion web/src/p2k16/web/core_blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
from p2k16.core.membership_management import member_create_checkout_session, member_customer_portal, \
get_membership, get_membership_payments, active_member, get_membership_fee
from p2k16.core.models import Account, Circle, Company, CompanyEmployee, CircleMember, BadgeDescription, \
CircleManagementStyle, Membership, StripePayment
CircleManagementStyle, Membership, StripePayment, \
AccountKeyType, AccountKey

from p2k16.core.models import AccountBadge
from p2k16.core.models import db
from p2k16.web.utils import validate_schema, require_circle_membership, DataServiceTool, ResourcesTool
Expand All @@ -26,6 +28,8 @@
bool_type = {"type": "boolean"}
management_style_type = {"enum": ["ADMIN_CIRCLE", "SELF_ADMIN"]}
stripe_pubkey = None
# also specified in models.py
account_key_type = {"enum": ["SSH", "WIREGUARD"]}

register_account_form = {
"type": "object",
Expand Down Expand Up @@ -124,6 +128,19 @@
"required": ["name", "contact"]
}

add_account_key_form = {
"type": "object",
"properties": {
"comment": nonempty_string,
"publicKey": nonempty_string,
"keyType": account_key_type,
},
"required": [
"comment",
"publicKey",
"keyType",
]
}

def model_to_json(obj) -> dict:
d = {}
Expand Down Expand Up @@ -185,6 +202,15 @@ def account_to_json(account: Account):
"phone": account.phone,
}}

def account_key_to_json(ak: AccountKey):
return {**model_to_json(ak), **{
"id": ak.id,
"account_id": ak.account.id,
"account_username": ak.account.username,
"comment": ak.comment,
"public_key": ak.public_key,
"key_type": ak.key_type.name,
}}

def profile_to_json(account: Account, circles: List[Circle], badges: Optional[List[AccountBadge]], full=False):
from .badge_blueprint import badge_to_json
Expand Down Expand Up @@ -469,6 +495,51 @@ def _manage_circle_membership(create: bool):
db.session.commit()
return jsonify(circle_to_json(circle, include_members=True))

###############################################################################
# AccountKey

def _return_account_key(account):
keys = AccountKey.find_by_account(account)
logger.info("keys: {}" % keys)
ret = [account_key_to_json(ak) for ak in
keys]

return jsonify(ret)
@registry.route('/data/account/key', methods=["GET"])
def data_account_keys():
account = flask_login.current_user.account

return _return_account_key(account)

@registry.route('/data/account/key', methods=["POST"])
@validate_schema(add_account_key_form)
def service_add_account_key():
account = flask_login.current_user.account
comment = request.json.get('comment')
public_key = request.json.get('publicKey')
key_type = AccountKeyType[request.json.get('keyType')]

key = AccountKey(account, comment, public_key, key_type)
db.session.add(key)
db.session.commit();

return _return_account_key(account)

@registry.route('/data/account/key/<int:key_id>', methods=["DELETE"])
def service_remove_account_key(key_id):
account = flask_login.current_user.account
key = AccountKey.find_by_id(key_id)

if key is None:
abort(404)

if key.account.id != account.id:
raise P2k16UserException("Key not owned by logged in user: {}".format(account.id))

db.session.delete(key)
db.session.commit()
return _return_account_key(account)


###############################################################################
# Membership
Expand Down
27 changes: 27 additions & 0 deletions web/src/p2k16/web/static/core-data-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,30 @@ function CoreDataService($http) {
return $http(req);
};

this.data_account_keys = function () {
var req = {};
req.method = 'GET';
req.url = '/data/account/key';
return $http(req);
};

this.service_add_account_key = function (payload) {
var req = {};
req.method = 'POST';
req.url = '/data/account/key';
req.data = payload;
return $http(req);
};

this.service_remove_account_key = function (key_id, payload) {
var req = {};
req.method = 'DELETE';
req.url = '/data/account/key';
req.url += '/' + key_id;
req.data = payload;
return $http(req);
};

this.membership_create_checkout_session = function (payload) {
var req = {};
req.method = 'POST';
Expand Down Expand Up @@ -214,6 +238,9 @@ CoreDataServiceResolvers.data_account_summary = function (CoreDataService, $rout
var account_id = $route.current.params.account_id;
return CoreDataService.data_account_summary(account_id).then(function (res) { return res.data; });
};
CoreDataServiceResolvers.data_account_keys = function (CoreDataService) {
return CoreDataService.data_account_keys().then(function (res) { return res.data; });
};
CoreDataServiceResolvers.data_circle = function (CoreDataService, $route) {
var circle_id = $route.current.params.circle_id;
return CoreDataService.data_circle(circle_id).then(function (res) { return res.data; });
Expand Down
69 changes: 64 additions & 5 deletions web/src/p2k16/web/static/my-profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ <h1>My profile</h1>

<form class="form-horizontal">
<div class="form-group">
<label for="name" class="col-sm-3 control-label">Old password</label>
<label for="name" class="col-sm-3 col-lg-2 control-label">Old password</label>
<div class="col-sm-4">
<input class="form-control" type="password" name="oldPassword" id="oldPassword"
ng-model="ctrl.changePasswordForm.oldPassword"/>
</div>
</div>
<div class="form-group">
<label for="name" class="col-sm-3 control-label">New password</label>
<label for="name" class="col-sm-3 col-lg-2 control-label">New password</label>
<div class="col-sm-4">
<input class="form-control" type="password" name="newPassword" id="newPassword"
ng-model="ctrl.changePasswordForm.newPassword"/>
</div>
</div>
<div class="form-group">
<label for="name" class="col-sm-3 control-label">New password</label>
<label for="name" class="col-sm-3 col-lg-2 control-label">New password</label>
<div class="col-sm-4">
<button class="btn btn-default" ng-click="ctrl.changePassword()">Change password</button>
</div>
Expand All @@ -30,7 +30,7 @@ <h1>My profile</h1>
<h3>Edit profile details</h3>
<form class="form-horizontal">
<div class="form-group">
<label for="phone" class="col-sm-3 control-label">Phone number</label>
<label for="phone" class="col-sm-3 col-lg-2 control-label">Phone number</label>
<div class="col-sm-4">
<input class="form-control"
type="text"
Expand All @@ -42,7 +42,7 @@ <h3>Edit profile details</h3>
</div>
</div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-3">
<div class="col-sm-4 col-sm-offset-3 col-lg-offset-2">
<button class="btn btn-default" ng-click="ctrl.saveProfile()">Save profile</button>
</div>
</div>
Expand Down Expand Up @@ -77,4 +77,63 @@ <h1>Box label</h1>
</div>
</div>

<h1>Account keys</h1>
<div class="list-group">
<div class="list-group-item" ng-repeat="key in ctrl.accountKeys">
<h4 class="list-group-item-header clearfix">
<button class="btn btn-danger btn-sm pull-right" ng-click="ctrl.removeAccountKey(key)">
<span class="glyphicon glyphicon-remove"></span> Remove
</button>
<span class="glyphicon" ng-class="{'glyphicon-console': key.key_type == 'SSH', 'glyphicon-cloud': key.key_type == 'WIREGUARD'}"></span>
<span class="comment">{{key.comment}}</span>
</h4>
</div>
</div>
<h3>Add key</h3>
<form class="form-horizontal">
<div class="form-group">
<label for="comment" class="col-sm-3 col-lg-2 control-label">Comment</label>
<div class="col-sm-7">
<input class="form-control"
type="text"
name="comment"
id="comment"
placeholder="Key comment"
ng-model="ctrl.newAccountKeyForm.comment"
autocomplete="none" />
</div>
</div>
<div class="form-group">
<label for="keyType" class="col-sm-3 col-lg-2 control-label">Key type</label>
<div class="col-sm-4">
<select
class="form-control"
name="keyType"
ng-model="ctrl.newAccountKeyForm.keyType">
<option value="SSH">SSH</option>
<option value="WIREGUARD">WireGuard</option>
</select>
</div>
</div>
<div class="form-group">
<label for="publicKey" class="col-sm-3 col-lg-2 control-label">Public key</label>
<div class="col-sm-7">
<textarea
style="resize: vertical"
class="form-control"
name="publicKey"
id="publicKey"
ng-model="ctrl.newAccountKeyForm.publicKey"
rows="7">
</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-3 col-lg-offset-2">
<button class="btn btn-default" ng-click="ctrl.addAccountKey()">Add account key</button>
</div>
</div>
</form>


</div>
2 changes: 1 addition & 1 deletion web/src/p2k16/web/static/p2k16/p2k16.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
div.error-container {
position: absolute;
position: fixed;
right: 3em;
top: 3em;
width: 25em;
Expand Down
Loading