diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts
index 365bb1765b..fdc9e94e4e 100644
--- a/packages/cli/src/Server.ts
+++ b/packages/cli/src/Server.ts
@@ -979,7 +979,7 @@ class App {
// Save the credentials in DB
await Db.collections.Credentials!.update(state.cid, newCredentialsData);
- res.sendFile(pathResolve('templates/oauth-callback.html'));
+ res.sendFile(pathResolve(__dirname, '../../templates/oauth-callback.html'));
});
diff --git a/packages/editor-ui/src/components/CredentialsEdit.vue b/packages/editor-ui/src/components/CredentialsEdit.vue
index 782e615a33..ed67e96279 100644
--- a/packages/editor-ui/src/components/CredentialsEdit.vue
+++ b/packages/editor-ui/src/components/CredentialsEdit.vue
@@ -34,11 +34,11 @@ import CredentialsInput from '@/components/CredentialsInput.vue';
import {
ICredentialsCreatedEvent,
ICredentialsDecryptedResponse,
- INodeProperties,
} from '@/Interface';
import {
ICredentialType,
+ INodeProperties,
} from 'n8n-workflow';
import mixins from 'vue-typed-mixins';
@@ -172,6 +172,42 @@ export default mixins(
},
},
methods: {
+ mergeCredentialProperties (mainProperties: INodeProperties[], addProperties: INodeProperties[]): void {
+ let existingIndex: number;
+ for (const property of addProperties) {
+ existingIndex = mainProperties.findIndex(element => element.name === property.name);
+
+ if (existingIndex === -1) {
+ // Property does not exist yet, so add
+ mainProperties.push(property);
+ } else {
+ // Property exists already, so overwrite
+ mainProperties[existingIndex] = property;
+ }
+ }
+ },
+ getCredentialProperties (name: string): INodeProperties[] {
+ const credentialsData = this.$store.getters.credentialType(name);
+
+ if (credentialsData === null) {
+ throw new Error(`Could not find credentials of type: ${name}`);
+ }
+
+ if (credentialsData.extends === undefined) {
+ return credentialsData.properties;
+ }
+
+ const combineProperties = [] as INodeProperties[];
+ for (const credentialsTypeName of credentialsData.extends) {
+ const mergeCredentialProperties = this.getCredentialProperties(credentialsTypeName);
+ this.mergeCredentialProperties(combineProperties, mergeCredentialProperties);
+ }
+
+ // The properties defined on the parent credentials take presidence
+ this.mergeCredentialProperties(combineProperties, credentialsData.properties);
+
+ return combineProperties;
+ },
getCredentialTypeData (name: string): ICredentialType | null {
let credentialData = this.$store.getters.credentialType(name);
@@ -179,25 +215,14 @@ export default mixins(
return credentialData;
}
+ // TODO: The credential-extend-resolve-logic is currently not needed in the backend
+ // as the whole credential data gets saved with the defaults. That logic should,
+ // however, probably also get improved in the future.
+
// Credentials extends another one. So get the properties of the one it
// extends and add them.
credentialData = JSON.parse(JSON.stringify(credentialData));
- let existingIndex: number;
- for (const credentialTypeName of credentialData.extends) {
- const data = this.$store.getters.credentialType(credentialTypeName);
-
- for (const property of data.properties) {
- existingIndex = credentialData.properties.findIndex(element => element.name === property.name);
-
- if (existingIndex === -1) {
- // Property does not exist yet, so add
- credentialData.properties.push(property);
- } else {
- // Property exists already, so overwrite
- credentialData.properties[existingIndex] = property;
- }
- }
- }
+ credentialData.properties = this.getCredentialProperties(credentialData.name);
return credentialData;
},
diff --git a/packages/editor-ui/src/components/CredentialsInput.vue b/packages/editor-ui/src/components/CredentialsInput.vue
index 708f72631e..76aa1c6672 100644
--- a/packages/editor-ui/src/components/CredentialsInput.vue
+++ b/packages/editor-ui/src/components/CredentialsInput.vue
@@ -41,18 +41,21 @@
-
-
- {{parameter.displayName}}:
-
-
-
-
-
-
-
-
-
+
+
+
+ {{parameter.displayName}}:
+
+
+
+
+
+
+
+
+
+
+
@@ -239,6 +242,13 @@ export default mixins(
return result;
},
+ displayNodeParameter (parameter: INodeProperties): boolean {
+ if (parameter.type === 'hidden') {
+ return false;
+ }
+
+ return true;
+ },
async oAuth2CredentialAuthorize () {
let url;
diff --git a/packages/nodes-base/credentials/GithubOAuth2Api.credentials.ts b/packages/nodes-base/credentials/GithubOAuth2Api.credentials.ts
index 0bf12444f2..9466ce447b 100644
--- a/packages/nodes-base/credentials/GithubOAuth2Api.credentials.ts
+++ b/packages/nodes-base/credentials/GithubOAuth2Api.credentials.ts
@@ -11,6 +11,26 @@ export class GithubOAuth2Api implements ICredentialType {
];
displayName = 'Github OAuth2 API';
properties = [
+ {
+ displayName: 'Authorization URL',
+ name: 'authUrl',
+ type: 'hidden' as NodePropertyTypes,
+ default: 'https://github.com/login/oauth/authorize',
+ required: true,
+ },
+ {
+ displayName: 'Access Token URL',
+ name: 'accessTokenUrl',
+ type: 'hidden' as NodePropertyTypes,
+ default: 'https://github.com/login/oauth/access_token',
+ required: true,
+ },
+ {
+ displayName: 'Scope',
+ name: 'scope',
+ type: 'hidden' as NodePropertyTypes,
+ default: 'repo,admin:repo_hook,admin:org,admin:org_hook,gist,notifications,user,write:packages,read:packages,delete:packages,worfklow',
+ },
{
displayName: 'Auth URI Query Parameters',
name: 'authQueryParameters',
diff --git a/packages/nodes-base/nodes/Github/GenericFunctions.ts b/packages/nodes-base/nodes/Github/GenericFunctions.ts
index 0b4c8452ab..97cc69aba4 100644
--- a/packages/nodes-base/nodes/Github/GenericFunctions.ts
+++ b/packages/nodes-base/nodes/Github/GenericFunctions.ts
@@ -1,3 +1,5 @@
+import { OptionsWithUri } from 'request';
+
import {
IExecuteFunctions,
IHookFunctions,
@@ -17,16 +19,12 @@ import {
* @returns {Promise}
*/
export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: object, query?: object): Promise { // tslint:disable-line:no-any
- const credentials = this.getCredentials('githubApi');
- if (credentials === undefined) {
- throw new Error('No credentials got returned!');
- }
+ const authenticationMethod = this.getNodeParameter('authentication', 0, 'accessToken') as string;
- const options = {
+ const options: OptionsWithUri = {
method,
headers: {
- 'Authorization': `token ${credentials.accessToken}`,
- 'User-Agent': credentials.user,
+ 'User-Agent': 'n8n',
},
body,
qs: query,
@@ -35,7 +33,16 @@ export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions,
};
try {
- return await this.helpers.request(options);
+ if (authenticationMethod === 'accessToken') {
+ const credentials = this.getCredentials('githubApi');
+ if (credentials === undefined) {
+ throw new Error('No credentials got returned!');
+ }
+ options.headers!.Authorization = `token ${credentials.accessToken}`;
+ return await this.helpers.request(options);
+ } else {
+ return await this.helpers.requestOAuth.call(this, 'githubOAuth2Api', options);
+ }
} catch (error) {
if (error.statusCode === 401) {
// Return a clear error
diff --git a/packages/nodes-base/nodes/Github/Github.node.ts b/packages/nodes-base/nodes/Github/Github.node.ts
index 6174a1bd47..81befb410c 100644
--- a/packages/nodes-base/nodes/Github/Github.node.ts
+++ b/packages/nodes-base/nodes/Github/Github.node.ts
@@ -33,9 +33,44 @@ export class Github implements INodeType {
{
name: 'githubApi',
required: true,
- }
+ displayOptions: {
+ show: {
+ authentication: [
+ 'accessToken',
+ ],
+ },
+ },
+ },
+ {
+ name: 'githubOAuth2Api',
+ required: true,
+ displayOptions: {
+ show: {
+ authentication: [
+ 'oauth2',
+ ],
+ },
+ },
+ },
],
properties: [
+ {
+ displayName: 'Authentication',
+ name: 'authentication',
+ type: 'options',
+ options: [
+ {
+ name: 'Access Token',
+ value: 'accessToken',
+ },
+ {
+ name: 'OAuth2',
+ value: 'oauth2',
+ },
+ ],
+ default: 'accessToken',
+ description: 'The resource to operate on.',
+ },
{
displayName: 'Resource',
name: 'resource',
@@ -1088,12 +1123,6 @@ export class Github implements INodeType {
const items = this.getInputData();
const returnData: IDataObject[] = [];
- const credentials = this.getCredentials('githubApi');
-
- if (credentials === undefined) {
- throw new Error('No credentials got returned!');
- }
-
// Operations which overwrite the returned data
const overwriteDataOperations = [
'file:create',