feat: add gitlab authentication
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
"dependencies": {
|
||||
"@automatisch/web": "0.1.0",
|
||||
"@bull-board/express": "^3.10.1",
|
||||
"@gitbeaker/node": "^35.6.0",
|
||||
"@graphql-tools/graphql-file-loader": "^7.3.4",
|
||||
"@graphql-tools/load": "^7.5.2",
|
||||
"@octokit/oauth-methods": "^1.2.6",
|
||||
|
12
packages/backend/src/apps/gitlab/assets/favicon.svg
Normal file
12
packages/backend/src/apps/gitlab/assets/favicon.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||
<svg width="256px" height="236px" viewBox="0 0 256 236" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M128.07485,236.074667 L128.07485,236.074667 L175.17885,91.1043048 L80.9708495,91.1043048 L128.07485,236.074667 L128.07485,236.074667 Z" fill="#E24329"></path>
|
||||
<path d="M128.07485,236.074423 L80.9708495,91.104061 L14.9557638,91.104061 L128.07485,236.074423 L128.07485,236.074423 Z" fill="#FC6D26"></path>
|
||||
<path d="M14.9558857,91.1044267 L14.9558857,91.1044267 L0.641828571,135.159589 C-0.663771429,139.17757 0.766171429,143.57955 4.18438095,146.06275 L128.074971,236.074789 L14.9558857,91.1044267 L14.9558857,91.1044267 Z" fill="#FCA326"></path>
|
||||
<path d="M14.9558857,91.1045486 L80.9709714,91.1045486 L52.6000762,3.79026286 C51.1408762,-0.703146667 44.7847619,-0.701927619 43.3255619,3.79026286 L14.9558857,91.1045486 L14.9558857,91.1045486 Z" fill="#E24329"></path>
|
||||
<path d="M128.07485,236.074423 L175.17885,91.104061 L241.193935,91.104061 L128.07485,236.074423 L128.07485,236.074423 Z" fill="#FC6D26"></path>
|
||||
<path d="M241.193935,91.1044267 L241.193935,91.1044267 L255.507992,135.159589 C256.813592,139.17757 255.38365,143.57955 251.96544,146.06275 L128.07485,236.074789 L241.193935,91.1044267 L241.193935,91.1044267 Z" fill="#FCA326"></path>
|
||||
<path d="M241.193935,91.1045486 L175.17885,91.1045486 L203.549745,3.79026286 C205.008945,-0.703146667 211.365059,-0.701927619 212.824259,3.79026286 L241.193935,91.1045486 L241.193935,91.1045486 Z" fill="#E24329"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
101
packages/backend/src/apps/gitlab/authentication.ts
Normal file
101
packages/backend/src/apps/gitlab/authentication.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { URLSearchParams } from 'url';
|
||||
import axios from 'axios';
|
||||
import crypto from 'crypto';
|
||||
import { Gitlab } from '@gitbeaker/node';
|
||||
import type {
|
||||
IAuthentication,
|
||||
IApp,
|
||||
IField,
|
||||
IJSONObject,
|
||||
} from '@automatisch/types';
|
||||
|
||||
export default class Authentication implements IAuthentication {
|
||||
appData: IApp;
|
||||
connectionData: IJSONObject;
|
||||
client: any;
|
||||
scopes = [
|
||||
'api',
|
||||
'profile',
|
||||
'email',
|
||||
];
|
||||
|
||||
constructor(appData: IApp, connectionData: IJSONObject) {
|
||||
this.connectionData = connectionData;
|
||||
this.appData = appData;
|
||||
|
||||
if (connectionData?.accessToken) {
|
||||
this.client = new Gitlab({
|
||||
host: this.host,
|
||||
oauthToken: connectionData?.accessToken as string,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get host() {
|
||||
return `https://${this.connectionData.host}`;
|
||||
}
|
||||
|
||||
get oauthRedirectUrl() {
|
||||
return this.appData.fields.find(
|
||||
(field: IField) => field.key == 'oAuthRedirectUrl'
|
||||
).value;
|
||||
}
|
||||
|
||||
async createAuthData() {
|
||||
const state = crypto.randomUUID();
|
||||
|
||||
const searchParams = new URLSearchParams({
|
||||
client_id: this.connectionData.applicationId as string,
|
||||
redirect_uri: this.oauthRedirectUrl,
|
||||
response_type: 'code',
|
||||
scope: this.scopes.join(' '),
|
||||
state,
|
||||
});
|
||||
|
||||
const url = `${this.host}/oauth/authorize?${searchParams.toString()}`;
|
||||
|
||||
return { url };
|
||||
}
|
||||
|
||||
async verifyCredentials() {
|
||||
const params = new URLSearchParams({
|
||||
client_id: this.connectionData.applicationId as string,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: this.oauthRedirectUrl,
|
||||
code: this.connectionData.oauthVerifier as string,
|
||||
client_secret: this.connectionData.secret as string,
|
||||
});
|
||||
const { data } = await axios.post(`${this.host}/oauth/token`, params.toString());
|
||||
const accessToken = data.access_token;
|
||||
|
||||
const client = new Gitlab({
|
||||
host: this.host,
|
||||
oauthToken: accessToken,
|
||||
});
|
||||
|
||||
const user = await client.Users.current();
|
||||
|
||||
return {
|
||||
host: this.connectionData.host as string,
|
||||
applicationId: this.connectionData.applicationId as string,
|
||||
secret: this.connectionData.secret,
|
||||
accessToken: data.access_token,
|
||||
refreshToken: data.refresh_token,
|
||||
expiresIn: data.expires_in,
|
||||
tokenType: data.token_type,
|
||||
userId: user.id,
|
||||
screenName: user.name,
|
||||
username: user.username,
|
||||
};
|
||||
}
|
||||
|
||||
async isStillVerified() {
|
||||
try {
|
||||
await this.client.Users.current();
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
0
packages/backend/src/apps/gitlab/index.d.ts
vendored
Normal file
0
packages/backend/src/apps/gitlab/index.d.ts
vendored
Normal file
15
packages/backend/src/apps/gitlab/index.ts
Normal file
15
packages/backend/src/apps/gitlab/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import Authentication from './authentication';
|
||||
import {
|
||||
IService,
|
||||
IAuthentication,
|
||||
IApp,
|
||||
IJSONObject,
|
||||
} from '@automatisch/types';
|
||||
|
||||
export default class Gitlab implements IService {
|
||||
authenticationClient: IAuthentication;
|
||||
|
||||
constructor(appData: IApp, connectionData: IJSONObject) {
|
||||
this.authenticationClient = new Authentication(appData, connectionData);
|
||||
}
|
||||
}
|
238
packages/backend/src/apps/gitlab/info.json
Normal file
238
packages/backend/src/apps/gitlab/info.json
Normal file
@@ -0,0 +1,238 @@
|
||||
{
|
||||
"name": "GitLab",
|
||||
"key": "gitlab",
|
||||
"iconUrl": "{BASE_URL}/apps/gitlab/assets/favicon.svg",
|
||||
"docUrl": "https://automatisch.io/docs/gitlab",
|
||||
"primaryColor": "2DAAE1",
|
||||
"fields": [
|
||||
{
|
||||
"key": "oAuthRedirectUrl",
|
||||
"label": "OAuth Redirect URL",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"readOnly": true,
|
||||
"value": "{WEB_APP_URL}/app/gitlab/connections/add",
|
||||
"placeholder": null,
|
||||
"description": "When asked to input an OAuth callback or redirect URL in GitLab OAuth, enter the URL above.",
|
||||
"docUrl": "https://automatisch.io/docs/gitlab#oauth-redirect-url",
|
||||
"clickToCopy": true
|
||||
},
|
||||
{
|
||||
"key": "host",
|
||||
"label": "GitLab Host",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"readOnly": false,
|
||||
"value": "gitlab.com",
|
||||
"placeholder": null,
|
||||
"description": "Only required if you host your own instance of GitLab. If you access GitLab by going to https://www.example.com, enter www.example.com here.",
|
||||
"docUrl": "https://automatisch.io/docs/gitlab#host",
|
||||
"clickToCopy": false
|
||||
},
|
||||
{
|
||||
"key": "applicationId",
|
||||
"label": "Application ID",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"readOnly": false,
|
||||
"value": null,
|
||||
"placeholder": null,
|
||||
"description": null,
|
||||
"docUrl": "https://automatisch.io/docs/gitlab#application-id",
|
||||
"clickToCopy": false
|
||||
},
|
||||
{
|
||||
"key": "secret",
|
||||
"label": "Secret",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"readOnly": false,
|
||||
"value": null,
|
||||
"placeholder": null,
|
||||
"description": null,
|
||||
"docUrl": "https://automatisch.io/docs/gitlab#secret",
|
||||
"clickToCopy": false
|
||||
}
|
||||
],
|
||||
"authenticationSteps": [
|
||||
{
|
||||
"step": 1,
|
||||
"type": "mutation",
|
||||
"name": "createConnection",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "key",
|
||||
"value": "{key}"
|
||||
},
|
||||
{
|
||||
"name": "formattedData",
|
||||
"value": null,
|
||||
"properties": [
|
||||
{
|
||||
"name": "host",
|
||||
"value": "{fields.host}"
|
||||
},
|
||||
{
|
||||
"name": "applicationId",
|
||||
"value": "{fields.applicationId}"
|
||||
},
|
||||
{
|
||||
"name": "secret",
|
||||
"value": "{fields.secret}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"type": "mutation",
|
||||
"name": "createAuthData",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "id",
|
||||
"value": "{createConnection.id}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"type": "openWithPopup",
|
||||
"name": "openAuthPopup",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "url",
|
||||
"value": "{createAuthData.url}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 4,
|
||||
"type": "mutation",
|
||||
"name": "updateConnection",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "id",
|
||||
"value": "{createConnection.id}"
|
||||
},
|
||||
{
|
||||
"name": "formattedData",
|
||||
"value": null,
|
||||
"properties": [
|
||||
{
|
||||
"name": "oauthVerifier",
|
||||
"value": "{openAuthPopup.code}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 5,
|
||||
"type": "mutation",
|
||||
"name": "verifyConnection",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "id",
|
||||
"value": "{createConnection.id}"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"reconnectionSteps": [
|
||||
{
|
||||
"step": 1,
|
||||
"type": "mutation",
|
||||
"name": "resetConnection",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "id",
|
||||
"value": "{connection.id}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"type": "mutation",
|
||||
"name": "updateConnection",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "id",
|
||||
"value": "{connection.id}"
|
||||
},
|
||||
{
|
||||
"name": "formattedData",
|
||||
"value": null,
|
||||
"properties": [
|
||||
{
|
||||
"name": "host",
|
||||
"value": "{fields.host}"
|
||||
},
|
||||
{
|
||||
"name": "applicationId",
|
||||
"value": "{fields.applicationId}"
|
||||
},
|
||||
{
|
||||
"name": "secret",
|
||||
"value": "{fields.secret}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"type": "mutation",
|
||||
"name": "createAuthData",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "id",
|
||||
"value": "{connection.id}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 4,
|
||||
"type": "openWithPopup",
|
||||
"name": "openAuthPopup",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "url",
|
||||
"value": "{createAuthData.url}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 5,
|
||||
"type": "mutation",
|
||||
"name": "updateConnection",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "id",
|
||||
"value": "{connection.id}"
|
||||
},
|
||||
{
|
||||
"name": "formattedData",
|
||||
"value": null,
|
||||
"properties": [
|
||||
{
|
||||
"name": "oauthVerifier",
|
||||
"value": "{openAuthPopup.code}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": 6,
|
||||
"type": "mutation",
|
||||
"name": "verifyConnection",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "id",
|
||||
"value": "{connection.id}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@@ -24,11 +24,7 @@ const createAuthData = async (
|
||||
|
||||
if (!connection.formattedData) { return null; }
|
||||
|
||||
const appInstance = new appClass(appData, {
|
||||
consumerKey: connection.formattedData.consumerKey,
|
||||
consumerSecret: connection.formattedData.consumerSecret,
|
||||
});
|
||||
|
||||
const appInstance = new appClass(appData, connection.formattedData);
|
||||
const authLink = await appInstance.authenticationClient.createAuthData();
|
||||
|
||||
await connection.$query().patch({
|
||||
|
@@ -133,6 +133,7 @@ enum AvailableAppsEnumType {
|
||||
firebase
|
||||
flickr
|
||||
github
|
||||
gitlab
|
||||
postgresql
|
||||
smtp
|
||||
twilio
|
||||
|
Reference in New Issue
Block a user