Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Finished scheme support #206

Merged
merged 5 commits into from
Aug 19, 2019
Merged
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
18 changes: 16 additions & 2 deletions packages/api-elements/lib/elements/AuthScheme.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AuthScheme extends ArrayElement {
/**
* @name transitions
* @type ArraySlice
* @memberof HttpMessagePayload.prototype
* @memberof AuthScheme.prototype
*/
get transitions() {
return this.children.filter(item => item.element === 'transition');
Expand All @@ -27,11 +27,25 @@ class AuthScheme extends ArrayElement {
/**
* @name members
* @type ArraySlice
* @memberof HttpMessagePayload.prototype
* @memberof AuthScheme.prototype
*/
get members() {
return this.children.filter(item => item.element === 'member');
}

/**
* @name grantTypeValue
* @memberof AuthScheme.prototype
*/
get grantTypeValue() {
const grantType = this.members.find(item => item.key.toValue() === 'grantType');

if (grantType && grantType.value) {
return grantType.value.toValue();
}

return undefined;
}
}

module.exports = AuthScheme;
65 changes: 64 additions & 1 deletion packages/api-elements/test/api-description-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,19 @@ describe('API description namespace', () => {
},
},
},
{
element: 'member',
content: {
key: {
element: 'string',
content: 'grantType',
},
value: {
element: 'string',
content: 'token',
},
},
},
{
element: 'transition',
attributes: {
Expand Down Expand Up @@ -1039,7 +1052,7 @@ describe('API description namespace', () => {

it('should contain members', () => {
const { members } = authScheme;
expect(members).to.have.length(1);
expect(members).to.have.length(2);
members.forEach((item) => {
expect(item).to.be.an.instanceof(MemberElement);
});
Expand All @@ -1052,6 +1065,56 @@ describe('API description namespace', () => {
expect(item).to.be.an.instanceof(Transition);
});
});

it('should retrieve grant type', () => {
expect(authScheme.grantTypeValue).to.equal('token');
});

it('without grant type should return undefined', () => {
const refracted = {
element: 'Token Auth Scheme',
meta: {
id: {
element: 'string',
content: 'Custom Token Auth',
},
},
content: [],
};

const element = namespace.fromRefract(refracted);
const authScheme = new AuthScheme(element.content, element.meta, element.attributes);

expect(authScheme.grantTypeValue).to.be.undefined;
});

it('without grant type value should return undefined', () => {
const refracted = {
element: 'Token Auth Scheme',
meta: {
id: {
element: 'string',
content: 'Custom Token Auth',
},
},
content: [
{
element: 'member',
content: {
key: {
element: 'string',
content: 'grantType',
},
},
},
],
};

const element = namespace.fromRefract(refracted);
const authScheme = new AuthScheme(element.content, element.meta, element.attributes);

expect(authScheme.grantTypeValue).to.be.undefined;
});
});

context('HTTP transaction element', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/fury-adapter-oas3-parser/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Key:
| responses | [~](#responses-object) |
| callbacks | [✕](https://github.com/apiaryio/api-elements.js/issues/74) |
| deprecated | ✕ |
| security | [✕](https://github.com/apiaryio/api-elements.js/issues/77) |
| security | [✕](https://github.com/apiaryio/api-elements.js/issues/329) |
| servers | [✕](https://github.com/apiaryio/api-elements.js/issues/76) |

## Parameter Object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,20 @@ function parseComponentsObject(context, element) {

object.forEach((value, key) => {
if (value) {
// eslint-disable-next-line no-param-reassign
value.meta.id = key.clone();
array.push(value);
if (value instanceof namespace.elements.AuthScheme) {
// eslint-disable-next-line no-param-reassign
value.id = key.clone();
array.push(value);

return;
}

// append oauth2 flow names
value.forEach((flow) => {
// eslint-disable-next-line no-param-reassign
flow.id = `${key.toValue()} ${flow.grantTypeValue}`;
array.push(flow);
});
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,25 @@ function parseOauthFlowObject(context, object) {
return scope;
}));

const parseUrl = pipeParseResult(namespace,
parseString(context, name, false),
(url) => {
const transition = new namespace.elements.Transition();

transition.href = url.value.clone();
transition.relation = url.key.clone();

// remove 'Url' from key
transition.relation.content = transition.relation.toValue().slice(0, -3);

return transition;
});

const parseMember = R.cond([
[hasKey('scopes'), R.compose(parseScopes, getValue)],
[hasKey('refreshUrl'), parseString(context, name, false)],
[hasKey('authorizationUrl'), parseString(context, name, false)],
[hasKey('tokenUrl'), parseString(context, name, false)],
[hasKey('refreshUrl'), parseUrl],
[hasKey('authorizationUrl'), parseUrl],
[hasKey('tokenUrl'), parseUrl],

// FIXME Support exposing extensions into parse result
[isExtension, () => new namespace.elements.ParseResult()],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ function parseOauthFlowsObject(context, object) {
authScheme.push(new namespace.elements.Member('grantType', grantTypes[member.key.toValue()]));
authScheme.push(member.value.getMember('scopes'));

R.filter(R.is(namespace.elements.Transition), member.value).forEach((item) => {
authScheme.push(item);
});

return authScheme;
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,23 @@ function parseOASObject(context, object) {
parseObject(context, name, parseMember, requiredKeys, ['components']),
(object) => {
const api = object.get('info');
const components = object.get('components');

if (components) {
const schemes = R.or(components.get('securitySchemes'), new namespace.elements.Array());

if (!schemes.isEmpty) {
api.push(new namespace.elements.Category(
schemes.content, { classes: ['authSchemes'] }
));
}
}

const resources = object.get('paths');
if (resources) {
api.content = api.content.concat(resources.content);
}

const components = object.get('components');
if (components) {
const schemas = R.or(components.get('schemas'), new namespace.elements.Array())
.content
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const R = require('ramda');
const {
isMember, isExtension, hasKey, getValue,
isArray, isMember, isExtension, hasKey, getValue,
} = require('../../predicates');
const {
createWarning,
createUnsupportedMemberWarning,
createInvalidMemberWarning,
createIdentifierNotUniqueWarning,
Expand All @@ -13,6 +14,7 @@ const parseObject = require('../parseObject');
const parseString = require('../parseString');
const parseResponsesObject = require('./parseResponsesObject');
const parseParameterObjects = require('./parseParameterObjects');
const parseSecurityRequirementObject = require('./parseSecurityRequirementObject');
const parseRequestBodyObject = require('./parseRequestBodyObject');
const parseReference = require('../parseReference');

Expand All @@ -21,7 +23,7 @@ const parseRequestBodyObjectOrRef = parseReference('requestBodies', parseRequest
const name = 'Operation Object';
const requiredKeys = ['responses'];
const unsupportedKeys = [
'tags', 'externalDocs', 'callbacks', 'deprecated', 'security',
'tags', 'externalDocs', 'callbacks', 'deprecated',
];
const isUnsupportedKey = R.anyPass(R.map(hasKey, unsupportedKeys));

Expand Down Expand Up @@ -102,13 +104,32 @@ function parseOperationObject(context, path, member) {
),
]));

const parseSecurity = pipeParseResult(namespace,
R.unless(isArray, createWarning(namespace, `'${name}' 'security' is not an array`)),
R.compose(R.chain(parseSecurityRequirementObject(context)), R.constructN(1, namespace.elements.Array)),
requirements => requirements.map((requirement) => {
if (requirement.length === 1) {
return requirement.get(0);
}

const link = new namespace.elements.Link();
link.relation = 'profile';
link.href = 'https://github.com/refractproject/rfcs/issues/39';

const allOf = new namespace.elements.Extension(requirement.content);
allOf.meta.set('links', new namespace.elements.Array([link]));

return allOf;
}));

const parseMember = R.cond([
[hasKey('summary'), parseString(context, name, false)],
[hasKey('description'), parseCopy(context, name, false)],
[hasKey('operationId'), pipeParseResult(namespace, parseString(context, name, false), parseOperationId)],
[hasKey('responses'), R.compose(parseResponsesObject(context), getValue)],
[hasKey('requestBody'), R.compose(parseRequestBodyObjectOrRef(context), getValue)],
[hasKey('parameters'), R.compose(parseParameterObjects(context, name), getValue)],
[hasKey('security'), R.compose(parseSecurity, getValue)],

[isUnsupportedKey, createUnsupportedMemberWarning(namespace, name)],

Expand Down Expand Up @@ -161,6 +182,13 @@ function parseOperationObject(context, path, member) {
}
}

const security = operation.get('security');
if (security) {
transactions.forEach((transaction) => {
transaction.attributes.set('authSchemes', security.clone());
});
}

return transition;
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,17 @@ function parseSecurityRequirementObject(context, object) {
const parseSecurityRequirement = pipeParseResult(namespace,
parseObject(context, name, parseMember),
(securityRequirement) => {
// TODO: expand oauth requirements into multiples depending on flows
const arr = new namespace.elements.Array([]);

securityRequirement.forEach((value, key) => {
let e;
const scopes = value.map(scope => scope.toValue());

if (scopes.length) {
e = new namespace.elements.Object({ scopes });
e = new namespace.elements.AuthScheme({ scopes });
} else {
e = new namespace.elements.Object({});
e = new namespace.elements.AuthScheme({});
}

e.element = key.toValue();
Expand Down
Loading