summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2019-02-14 12:08:19 -0500
committerDrew DeVault <sir@cmpwn.com>2019-02-14 12:08:19 -0500
commit8c828abeb29a81c9f3406d7d1a8e6a9a5b1d7a80 (patch)
treef8a4281af705b5f90c654001c0e1cec37a435257
parent411c109a0f3b95445097620d21eccbf1cef3267c (diff)
Fetch user SSH keys from meta.sr.ht
-rw-r--r--gitsrht/alembic/versions/4b8847962942_add_ssh_key_table.py27
-rw-r--r--gitsrht/app.py4
-rw-r--r--gitsrht/service.py51
-rw-r--r--gitsrht/types/__init__.py2
-rw-r--r--gitsrht/types/sshkey.py15
5 files changed, 93 insertions, 6 deletions
diff --git a/gitsrht/alembic/versions/4b8847962942_add_ssh_key_table.py b/gitsrht/alembic/versions/4b8847962942_add_ssh_key_table.py
new file mode 100644
index 0000000..dbaf845
--- /dev/null
+++ b/gitsrht/alembic/versions/4b8847962942_add_ssh_key_table.py
@@ -0,0 +1,27 @@
+"""Add ssh key table
+
+Revision ID: 4b8847962942
+Revises: 27ad57b7c4a5
+Create Date: 2019-02-14 12:04:24.026615
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '4b8847962942'
+down_revision = '27ad57b7c4a5'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.create_table('sshkey',
+ sa.Column("id", sa.Integer, primary_key=True),
+ sa.Column("user_id", sa.Integer, sa.ForeignKey('user.id'), nullable=False),
+ sa.Column("meta_id", sa.Integer, nullable=False, unique=True, index=True),
+ sa.Column("key", sa.String(4096), nullable=False),
+ sa.Column("fingerprint", sa.String(512), nullable=False))
+
+
+def downgrade():
+ op.drop_table('sshkey')
diff --git a/gitsrht/app.py b/gitsrht/app.py
index c4b8663..19d580e 100644
--- a/gitsrht/app.py
+++ b/gitsrht/app.py
@@ -6,7 +6,7 @@ from functools import lru_cache
from gitsrht import urls
from gitsrht.git import commit_time, trim_commit
from gitsrht.repos import GitRepoApi
-from gitsrht.service import GitOAuthService, webhooks_notify
+from gitsrht.service import oauth_service, webhooks_notify
from gitsrht.types import Access, Redirect, Repository, User
from scmsrht.flask import ScmSrhtFlask
from srht.config import cfg
@@ -21,7 +21,7 @@ class GitApp(ScmSrhtFlask):
access_class=Access, redirect_class=Redirect,
repository_class=Repository, user_class=User,
repo_api=GitRepoApi(),
- oauth_service=GitOAuthService())
+ oauth_service=oauth_service)
from gitsrht.blueprints.repo import repo
from gitsrht.blueprints.stats import stats
diff --git a/gitsrht/service.py b/gitsrht/service.py
index 67398bd..e7e0cda 100644
--- a/gitsrht/service.py
+++ b/gitsrht/service.py
@@ -1,6 +1,7 @@
from flask import Blueprint, request, url_for
-from gitsrht.types import User, OAuthToken
+from gitsrht.types import User, OAuthToken, SSHKey
from srht.api import get_results
+from srht.database import db
from srht.config import cfg
from srht.flask import csrf_bypass
from srht.oauth import AbstractOAuthService
@@ -8,6 +9,7 @@ import json
import requests
origin = cfg("git.sr.ht", "origin")
+meta_origin = cfg("meta.sr.ht", "origin")
client_id = cfg("git.sr.ht", "oauth-client-id")
client_secret = cfg("git.sr.ht", "oauth-client-secret")
builds_client_id = cfg("builds.sr.ht", "oauth-client-id", default=None)
@@ -20,6 +22,25 @@ class GitOAuthService(AbstractOAuthService):
] if builds_client_id else []),
token_class=OAuthToken, user_class=User)
+ def ensure_user_sshkey(self, user, meta_key):
+ """
+ Ensures this SSH key is registered with this user, and returns True if
+ their authorized_keys file needs to be regenerated.
+
+ `meta_key` should be the key object returned from meta.sr.ht.
+ """
+ key = SSHKey.query.filter(
+ SSHKey.meta_id == meta_key["id"]).one_or_none()
+ if key:
+ return False
+ key = SSHKey()
+ key.user_id = user.id
+ key.meta_id = meta_key["id"]
+ key.key = meta_key["key"]
+ key.fingerprint = meta_key["fingerprint"]
+ db.session.add(key)
+ return True
+
def ensure_meta_webhooks(self, user, webhooks):
webhook_url = origin + url_for("webhooks.notify.notify_keys")
webhooks.update({
@@ -27,6 +48,16 @@ class GitOAuthService(AbstractOAuthService):
})
super().ensure_meta_webhooks(user, webhooks)
+ def lookup_or_register(self, token, token_expires, scopes):
+ user = super().lookup_or_register(token, token_expires, scopes)
+ keys_url = f"{meta_origin}/api/user/ssh-keys"
+ for key in get_results(keys_url, user.oauth_token):
+ self.ensure_user_sshkey(user, key)
+ db.session.commit()
+ return user
+
+oauth_service = GitOAuthService()
+
webhooks_notify = Blueprint("webhooks.notify", __name__)
@csrf_bypass
@@ -34,6 +65,18 @@ webhooks_notify = Blueprint("webhooks.notify", __name__)
def notify_keys():
payload = json.loads(request.data.decode('utf-8'))
event = request.headers.get("X-Webhook-Event")
- # TODO: Store these keys in the database
- print(event, payload)
- return "Thanks!"
+ # TODO: Regenerate authorized_keys
+ if event == "ssh-key:add":
+ user = User.query.filter(
+ User.username == payload["owner"]["name"]).one_or_none()
+ oauth_service.ensure_user_sshkey(user, payload)
+ db.session.commit()
+ return "Added user's SSH key, thanks!"
+ elif event == "ssh-key:remove":
+ key = SSHKey.query.filter(
+ SSHKey.meta_id == payload["id"]).one_or_none()
+ if key:
+ db.session.delete(key)
+ db.session.commit()
+ return "Removed user's SSH key, thanks!"
+ return f"Unexpected event {event}"
diff --git a/gitsrht/types/__init__.py b/gitsrht/types/__init__.py
index 69a8ddd..390fb62 100644
--- a/gitsrht/types/__init__.py
+++ b/gitsrht/types/__init__.py
@@ -17,3 +17,5 @@ class Redirect(Base, BaseRedirectMixin):
class Repository(Base, BaseRepositoryMixin):
pass
+
+from gitsrht.types.sshkey import SSHKey
diff --git a/gitsrht/types/sshkey.py b/gitsrht/types/sshkey.py
new file mode 100644
index 0000000..9157e24
--- /dev/null
+++ b/gitsrht/types/sshkey.py
@@ -0,0 +1,15 @@
+import sqlalchemy as sa
+import sqlalchemy_utils as sau
+from srht.database import Base
+
+class SSHKey(Base):
+ __tablename__ = 'sshkey'
+ id = sa.Column(sa.Integer, primary_key=True)
+ user_id = sa.Column(sa.Integer, sa.ForeignKey('user.id'), nullable=False)
+ user = sa.orm.relationship('User', backref=sa.orm.backref('ssh_keys'))
+ meta_id = sa.Column(sa.Integer, nullable=False, unique=True, index=True)
+ key = sa.Column(sa.String(4096), nullable=False)
+ fingerprint = sa.Column(sa.String(512), nullable=False)
+
+ def __repr__(self):
+ return '<SSHKey {} {}>'.format(self.id, self.fingerprint)