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

fix auth #109

Merged
merged 10 commits into from
Oct 13, 2021
Merged
Show file tree
Hide file tree
Changes from 7 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
21 changes: 18 additions & 3 deletions packages/api-explorer/__tests__/AuthBox.test.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { shallowWithIntl, mountWithIntl } from 'enzyme-react-intl';

import AuthBox from '../src/AuthBox';
import AuthForm from '../src/components/AuthForm'
import AuthForm from '../src/components/AuthForm';

const Oas = require('../src/lib/Oas.js');
const multipleSecurities = require('./fixtures/multiple-securities/oas');
const Oas = require('../src/lib/Oas');
const multipleSecurities = require('./fixtures/multiple-securities/oas.json');

const oas = new Oas(multipleSecurities);

Expand Down Expand Up @@ -34,3 +35,17 @@ test('should display a single heading for single auth type', () => {

expect(popoverContent.find(AuthForm)).toHaveLength(1);
});

test('should display a reset button', () => {
// This object is retrieved from OAS library while running in prod.
const securityTypes = {
"Header Auth":[{"type":"auth","flows":{"implicit":{"authorizationUrl":"http://petstore.swagger.io/oauth/dialog","scopes":{"write:pets":"modify pets in your account","read:pets":"read your pets"}}},"_key":"petstore_auth"}],
}
const security = [{"Header Auth": []}]
const authBox = mountWithIntl(<AuthBox {...props} securityTypes={securityTypes} security={security} />);
const popoverContent = shallowWithIntl(<div>{authBox.find('Popover').prop('content')}</div>)
const button = popoverContent.find('Button')

expect(button).toHaveLength(1);
expect(button.find(FormattedMessage).prop('id')).toBe('reset');
});
18 changes: 13 additions & 5 deletions packages/api-explorer/__tests__/SecurityInput.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,35 @@ const baseProps = {
test('should render an Oauth2 component if type is oauth2', () => {
const props = { scheme: { type: 'oauth2', _key: 'auth', name: 'auth' } };
const securityInput = shallow(<SecurityInput {...props} {...baseProps} />);
expect(securityInput.find('Oauth2').length).toBe(1);
const oauth2 = securityInput.find('Oauth2')
expect(oauth2.length).toBe(1);
expect(oauth2.html()).toMatchSnapshot();
});

test('should render an ApiKey component if type is apiKey', () => {
const props = { scheme: { type: 'apiKey', _key: 'auth', name: 'auth' } };
const securityInput = shallow(<SecurityInput {...props} {...baseProps} />);
expect(securityInput.find('ApiKey').length).toBe(1);
const apiKey = securityInput.find('ApiKey');
expect(apiKey.length).toBe(1);
expect(apiKey.html()).toMatchSnapshot();
});

test('should render a Basic component if type is http/basic', () => {
const props = { scheme: { type: 'http', scheme: 'basic', _key: 'auth', name: 'auth' } };
const securityInput = shallow(<SecurityInput {...props} {...baseProps} auth={{ auth: {} }} />);
expect(securityInput.find('Basic').length).toBe(1);
const basic = securityInput.find('Basic')
expect(basic.length).toBe(1);
expect(basic.html()).toMatchSnapshot();
});

test('should render an Oauth2 component if type is http/bearer', () => {
const props = { scheme: { type: 'http', scheme: 'bearer', _key: 'auth', name: 'auth' } };
const securityInput = shallow(
<SecurityInput {...props} {...baseProps} auth={{ auth: '123456' }} />,
);
expect(securityInput.find('Oauth2').length).toBe(1);
const oauth2 = securityInput.find('Oauth2')
expect(oauth2.length).toBe(1);
expect(oauth2.html()).toMatchSnapshot();
});

describe('oauth2', () => {
Expand Down Expand Up @@ -115,7 +123,7 @@ describe('apiKey', () => {
const onChange = jest.fn();
const securityInput = mount(<SecurityInput {...props} {...baseProps} onChange={onChange} />);

expect(securityInput.find('label').text()).toBe('api_key');
expect(securityInput.find('label').text()).toBe('Api_key');
});
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render a Basic component if type is http/basic 1`] = `"<div class=\\"row\\"><div class=\\"col-xs-6\\"><label for=\\"user\\" style=\\"padding:0\\"><span>Username</span></label><input type=\\"text\\" name=\\"user\\" style=\\"border:1px solid #ddd;border-radius:2px;padding:5px 7px;width:100%;font-size:13px;color:#666;min-width:100px\\" value=\\"\\"/></div><div class=\\"col-xs-6\\"><label for=\\"password\\" style=\\"padding:0\\"><span>Password</span></label><input type=\\"text\\" name=\\"pass\\" style=\\"border:1px solid #ddd;border-radius:2px;padding:5px 7px;width:100%;font-size:13px;color:#666;min-width:100px\\" value=\\"\\"/></div></div>"`;

exports[`should render an ApiKey component if type is apiKey 1`] = `"<div><div><label for=\\"apiKey\\" style=\\"padding:0\\">Auth</label></div><div><input type=\\"text\\" style=\\"border:1px solid #ddd;border-radius:2px;padding:5px 7px;width:100%;font-size:13px;color:#666;min-width:100px\\" value=\\"\\"/></div></div>"`;

exports[`should render an Oauth2 component if type is http/bearer 1`] = `"<section><div><div><label for=\\"apiKey\\" style=\\"padding:0\\"><span>Authorization</span></label></div><div><input type=\\"text\\" name=\\"apiKey\\" style=\\"border:1px solid #ddd;border-radius:2px;padding:5px 7px;width:100%;font-size:13px;color:#666;min-width:100px\\" value=\\"123456\\"/></div></div></section>"`;

exports[`should render an Oauth2 component if type is oauth2 1`] = `"<section><div><div><label for=\\"apiKey\\" style=\\"padding:0\\"><span>Authorization</span></label></div><div><input type=\\"text\\" name=\\"apiKey\\" style=\\"border:1px solid #ddd;border-radius:2px;padding:5px 7px;width:100%;font-size:13px;color:#666;min-width:100px\\" value=\\"\\"/></div></div></section>"`;
4 changes: 2 additions & 2 deletions packages/api-explorer/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
"error": "Error",
"error.endpoint.render": "There was an error rendering this endpoint.",
"error.explorer.render": "There was an error rendering the API Explorer.",
"auth.basic.username": "username",
"auth.basic.password": "password",
"auth.basic.username": "Username",
"auth.basic.password": "Password",
"auth.oauth2.info": "Authenticate via OAuth2",
"auth.oauth2.authorization": "Authorization",
"auth.oauth2.bearer": "Bearer",
Expand Down
4 changes: 2 additions & 2 deletions packages/api-explorer/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
"error": "Errore",
"error.endpoint.render": "C'è stato un errore nel renderizzare questo endpoint.",
"error.explorer.render": "C'è stato un errore nel renderizzare l'API Explorer.",
"auth.basic.username": "username",
"auth.basic.password": "password",
"auth.basic.username": "Username",
"auth.basic.password": "Password",
"auth.oauth2.info": "Autenticati via OAuth2",
"auth.oauth2.authorization": "Autorizzazione",
"auth.oauth2.bearer": "Bearer",
Expand Down
97 changes: 53 additions & 44 deletions packages/api-explorer/src/AuthBox.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {Component, Fragment} from 'react'
import PropTypes from 'prop-types';
import {injectIntl, FormattedMessage, intlShape} from 'react-intl';
import {Icon, Popover, Alert, Button} from 'antd'
import {FormattedMessage, injectIntl} from 'react-intl';
import {Alert, Button, Icon, Popover} from 'antd'
import flatten from 'lodash.flatten'
import uniq from 'lodash.uniq'

Expand All @@ -27,30 +27,54 @@ function filterSecurityScheme(security, securitySchemes) {
}

class AuthBox extends Component {

renderIconLock() {
const {toggle, open} = this.props
return(
<Icon type={open ? 'unlock' : 'lock'} onClick={toggle} />
const { toggle, open } = this.props

const type = open ? 'unlock' : 'lock'

return (
<Icon
type={type}
onClick={toggle}
/>
)
}

renderAuthAlert() {
const {needsAuth, intl} = this.props

const message = intl.formatMessage({id:'warning', defaultMessage: 'Warning'})
const description = intl.formatMessage({id:'api.auth.required', defaultMessage: 'Authentication is required for this endpoint'})
return(
needsAuth ?
<Alert
message={message}
description={description}
type="warning"
showIcon
/> :
const { needsAuth } = this.props

const message = <FormattedMessage id='warning' defaultMessage='Warning' />
const description = <FormattedMessage id='api.auth.required' defaultMessage='Authentication is required for this endpoint' />

return( needsAuth ?
ilteoood marked this conversation as resolved.
Show resolved Hide resolved
ilteoood marked this conversation as resolved.
Show resolved Hide resolved
<Alert
message={message}
description={description}
type="warning"
showIcon
style={{marginBottom: '20px'}}
/> :
null
)
}

renderResetButton() {
const {showReset, onReset} = this.props

return (
<Button
disabled={!showReset}
ghost
onClick={onReset}
style={{marginTop: '20px', width: '100%'}}
type={'danger'}
>
<FormattedMessage id="reset" defaultMessage="Reset" />
</Button>
)
}

renderSecurityBox() {
const {
securityTypes,
Expand All @@ -59,55 +83,41 @@ class AuthBox extends Component {
onChange,
oauth,
auth,
authInputRef,
showReset,
onReset
authInputRef
} = this.props

return(
return (
<Fragment>
{this.renderAuthAlert()}
<AuthForm
onChange={onChange}
onSubmit={onSubmit}
authInputRef={authInputRef}
auth={auth}
oauth={oauth}
securitySchemes={security ? filterSecurityScheme(security,securityTypes) : {}}
securitySchemes={security ?
filterSecurityScheme(security, securityTypes) :
{}
}
/>
{
showReset ?
<div style={{padding: 5}}>
<Button
onClick={onReset}
type={'danger'}
size={'small'}
>
<FormattedMessage
id="reset"
defaultMessage="Reset"
/>
</Button>
</div>
: null
}
{this.renderAuthAlert()}
{this.renderResetButton()}
</Fragment>
)
}

render() {
const {securityTypes, onVisibleChange} = this.props
const { securityTypes, onVisibleChange } = this.props

if (Object.keys(securityTypes).length === 0) return null;

return (
<Popover
content={this.renderSecurityBox()}
getPopupContainer={triggerNode => triggerNode}
ilteoood marked this conversation as resolved.
Show resolved Hide resolved
style={{padding: 0}}
trigger={'click'}
visible={this.props.open}
onVisibleChange={(visibility) => {
onVisibleChange(visibility)
}}
onVisibleChange={onVisibleChange}
>
{this.renderIconLock()}
</Popover>
Expand Down Expand Up @@ -156,7 +166,6 @@ AuthBox.propTypes = {
auth: PropTypes.shape({}),
onReset: PropTypes.func,
showReset: PropTypes.bool,
intl: intlShape.isRequired,
onVisibleChange: PropTypes.func,
security: PropTypes.arrayOf(PropTypes.object)
};
Expand Down
2 changes: 1 addition & 1 deletion packages/api-explorer/src/Doc.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class Doc extends React.Component {
this.authInput.focus();
}
this.setState({ needsAuth: true });
}, 600);
});
return false;
}
this.setState({ loading: true, showAuthBox: false, needsAuth: false });
Expand Down
4 changes: 3 additions & 1 deletion packages/api-explorer/src/PathUrl.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ function renderButtonTry(loading, onSubmit, error) {
type={error ? 'danger' : 'primary'}
loading={loading}
>
{error ? <FormattedMessage id="error" defaultMessage="Error" /> : <FormattedMessage id="api.try" defaultMessage="Try It" />}
{error ?
<FormattedMessage id="error" defaultMessage="Error" /> :
<FormattedMessage id="api.try" defaultMessage="Try It" />}
</Button>
)
}
Expand Down
14 changes: 9 additions & 5 deletions packages/api-explorer/src/SecurityInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@ class Input extends React.Component {
}

function SecurityInput(props) {
const {auth, scheme} = props
function change(value) {
return props.onChange({ [scheme._key]: value });
}
const { auth, scheme } = props

const change = (value) => props.onChange({ [scheme._key]: value });

switch (scheme.type) {
case 'apiKey':
Expand Down Expand Up @@ -69,7 +68,12 @@ function SecurityInput(props) {
}
if (scheme.scheme === 'bearer') {
return (
<Oauth2 {...props} apiKey={auth[scheme._key]} change={change} Input={Input} />
<Oauth2
{...props}
apiKey={auth[scheme._key]}
change={change}
Input={Input}
/>
);
}
break;
Expand Down
Loading