From cad8197a819fa3f002dac85dea3c520e1faafbe6 Mon Sep 17 00:00:00 2001 From: Arian Rahimi Date: Sun, 19 Jan 2020 12:52:06 +0330 Subject: [PATCH] feat(security token): security token manager implemented security token manager flow implemented. token examples now can be add to store and components can listen to store change to get tokens submitted by the user --- demo/openapi.yaml | 2 - demo/ssr/index.ts | 12 +-- package.json | 2 - .../SecuritySchemes/SecuritySchemes.tsx | 51 +++++++++-- src/components/TokenGroup/TokenGroup.tsx | 84 +++++++++++++++++++ src/components/index.ts | 1 + src/services/models/SecuritySchemes.ts | 9 ++ src/theme.ts | 2 + yarn.lock | 15 ++-- 9 files changed, 153 insertions(+), 25 deletions(-) create mode 100644 src/components/TokenGroup/TokenGroup.tsx diff --git a/demo/openapi.yaml b/demo/openapi.yaml index b7c1833a..48a4d274 100644 --- a/demo/openapi.yaml +++ b/demo/openapi.yaml @@ -38,8 +38,6 @@ info: OAuth2 - an open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications. - - version: 1.0.0 title: Swagger Petstore termsOfService: 'http://swagger.io/terms/' diff --git a/demo/ssr/index.ts b/demo/ssr/index.ts index baac5331..142a58ef 100644 --- a/demo/ssr/index.ts +++ b/demo/ssr/index.ts @@ -1,10 +1,10 @@ -import { renderToString } from 'react-dom/server'; -import * as React from 'react'; -import { ServerStyleSheet } from 'styled-components'; -// @ts-ignore -import { Redoc, createStore } from '../../'; import { readFileSync } from 'fs'; import { resolve } from 'path'; +import * as React from 'react'; +import { renderToString } from 'react-dom/server'; +import { ServerStyleSheet } from 'styled-components'; + +import { createStore, Redoc } from '../../'; const yaml = require('yaml-js'); const http = require('http'); @@ -19,7 +19,7 @@ const server = http.createServer(async (request, response) => { fs.createReadStream('bundles/redoc.standalone.js', 'utf8').pipe(response); } else if (request.url === '/') { const spec = yaml.load(readFileSync(resolve(__dirname, '../openapi.yaml'))); - let store = await createStore(spec, 'path/to/spec.yaml'); + const store = await createStore(spec, 'path/to/spec.yaml'); const sheet = new ServerStyleSheet(); diff --git a/package.json b/package.json index fd15eb07..a0ec70b3 100644 --- a/package.json +++ b/package.json @@ -136,8 +136,6 @@ }, "dependencies": { "classnames": "^2.2.6", - "@types/chai": "4.1.3", - "@types/tapable": "1.0.2", "ajv": "^6.4.0", "ajv-errors": "^1.0.0", "brace": "^0.11.1", diff --git a/src/components/SecuritySchemes/SecuritySchemes.tsx b/src/components/SecuritySchemes/SecuritySchemes.tsx index fc5f3bc0..ebae4e44 100644 --- a/src/components/SecuritySchemes/SecuritySchemes.tsx +++ b/src/components/SecuritySchemes/SecuritySchemes.tsx @@ -1,8 +1,10 @@ +import { observer } from 'mobx-react'; import * as React from 'react'; +import { TokenGroup } from '..'; + +import { DarkRightPanel, H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements'; import { SecuritySchemesModel } from '../../services/models'; - -import { H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements'; import { OpenAPISecurityScheme } from '../../types'; import { titleize } from '../../utils/helpers'; import { Markdown } from '../Markdown/Markdown'; @@ -18,11 +20,12 @@ const AUTH_TYPES = { export interface OAuthFlowProps { type: string; flow: OpenAPISecurityScheme['flows'][keyof OpenAPISecurityScheme['flows']]; + token?: string; } export class OAuthFlow extends React.PureComponent { render() { - const { type, flow } = this.props; + const { type, flow, token } = this.props; return ( {type} OAuth Flow @@ -56,6 +59,7 @@ export class OAuthFlow extends React.PureComponent { ))} + {token} ); } @@ -65,7 +69,31 @@ export interface SecurityDefsProps { securitySchemes: SecuritySchemesModel; } -export class SecurityDefs extends React.PureComponent { +export interface SecurityDefsState { + tokens: Dict; +} + +@observer +export class SecurityDefs extends React.PureComponent { + + state = { + tokens: {}, + }; + + mutateToken = (scheme, id) => { + return () => { + scheme.setToken(this.state.tokens[id]); + }; + }; + + setToken = id => { + return token => { + const tokens = this.state.tokens; + tokens[id] = token; + this.setState({tokens}); + }; + }; + render() { return this.props.securitySchemes.schemes.map(scheme => (
@@ -82,22 +110,26 @@ export class SecurityDefs extends React.PureComponent { Security scheme type: {AUTH_TYPES[scheme.type] || scheme.type} + Value {scheme.apiKey ? ( {titleize(scheme.apiKey.in || '')} parameter name: {scheme.apiKey.name} + {scheme.token} ) : scheme.http ? ( [ HTTP Authorization Scheme {scheme.http.scheme} + {scheme.token} , scheme.http.scheme === 'bearer' && scheme.http.bearerFormat && ( Bearer format "{scheme.http.bearerFormat}" + {scheme.token} ), ] @@ -109,16 +141,25 @@ export class SecurityDefs extends React.PureComponent { {scheme.openId.connectUrl} + {scheme.token} ) : scheme.flows ? ( Object.keys(scheme.flows).map(type => ( - + )) ) : null} + + +
)); diff --git a/src/components/TokenGroup/TokenGroup.tsx b/src/components/TokenGroup/TokenGroup.tsx new file mode 100644 index 00000000..fd189e31 --- /dev/null +++ b/src/components/TokenGroup/TokenGroup.tsx @@ -0,0 +1,84 @@ +import * as React from 'react'; +import {Button, RightPanelHeader} from '../../common-elements'; +import styled from '../../styled-components'; + +const SaveTokenButton = styled(Button)` + padding: 10px 30px; + border-radius: 0 4px 4px 0; + cursor: pointer; + text-align: center; + outline: none; + margin: 0 + min-width: 60px; + max-width: 100px; + font-weight: bold; + flex: 1 1; + order: 2; +`; + +const TokenTextField = styled.input` + padding: 10px 30px 10px 20px; + border-radius: 4px 0 0 4px; + background-color: ${props => props.theme.codeSample.backgroundColor}; + color: ${props => props.theme.codeSample.textColor} + white-space: nowrap; + align-items: center; + border: none; + direction: ltr; + min-width: 300px; + flex: 4 1; + order: 1; +`; + +const TokenGroupContainer = styled.div` + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-items: stretch; + align-content: flex-start; +`; + +const Description = styled.p` + color: white; +`; + +interface TokenGroupProps { + title: string; + description?: string; + onSubmit: () => void; + onChange: (value: string) => void; +} + +export class TokenGroup extends React.PureComponent { + constructor(props) { + super(props); + this.submit = this.submit.bind(this); + this.change = this.change.bind(this); + } + + submit() { + this.props.onSubmit(); + } + + change(e) { + this.props.onChange(e.target.value); + } + + render() { + return ( + <> + + {this.props.title} + + + + Save + + + {this.props.description} + + + ); + } +} diff --git a/src/components/index.ts b/src/components/index.ts index 0c7c19cb..3f88edd1 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -30,3 +30,4 @@ export * from './StickySidebar/StickyResponsiveSidebar'; export * from './SearchBox/SearchBox'; export * from './SchemaDefinition/SchemaDefinition'; export * from './SourceCode/SourceCode'; +export * from './TokenGroup/TokenGroup'; diff --git a/src/services/models/SecuritySchemes.ts b/src/services/models/SecuritySchemes.ts index fc5deda8..2fb62f92 100644 --- a/src/services/models/SecuritySchemes.ts +++ b/src/services/models/SecuritySchemes.ts @@ -1,3 +1,4 @@ +import {observable} from 'mobx'; import { OpenAPISecurityScheme, Referenced } from '../../types'; import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils/openapi'; import { OpenAPIParser } from '../OpenAPIParser'; @@ -22,6 +23,9 @@ export class SecuritySchemeModel { connectUrl: string; }; + @observable + token?: string = ''; + constructor(parser: OpenAPIParser, id: string, scheme: Referenced) { const info = parser.deref(scheme); this.id = id; @@ -52,9 +56,14 @@ export class SecuritySchemeModel { this.flows = info.flows; } } + + setToken(token: string) { + this.token = token; + } } export class SecuritySchemesModel { + @observable schemes: SecuritySchemeModel[]; constructor(parser: OpenAPIParser) { diff --git a/src/theme.ts b/src/theme.ts index 6b20de7b..812be850 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -149,6 +149,7 @@ const defaultTheme: ThemeInterface = { }, codeSample: { backgroundColor: ({ rightPanel }) => darken(0.1, rightPanel.backgroundColor), + textColor: ({ rightPanel }) => rightPanel.textColor, }, styledPre: { maxHeight: '500px', @@ -324,6 +325,7 @@ export interface ResolvedThemeInterface { }; codeSample: { backgroundColor: string; + textColor: string; }; extensionsHook?: (name: string, props: any) => string; diff --git a/yarn.lock b/yarn.lock index ff531145..3c0db313 100644 --- a/yarn.lock +++ b/yarn.lock @@ -923,10 +923,10 @@ dependencies: "@babel/types" "^7.3.0" -"@types/chai@4.1.3": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.3.tgz#b8a74352977a23b604c01aa784f5b793443fb7dc" - integrity sha512-f5dXGzOJycyzSMdaXVhiBhauL4dYydXwVpavfQ1mVCaGjR56a9QfklXObUxlIY9bGTmCPHEEZ04I16BZ/8w5ww== +"@types/chai@4.1.7": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a" + integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA== "@types/cheerio@*": version "0.22.12" @@ -1132,16 +1132,11 @@ "@types/react-native" "*" csstype "^2.2.0" -"@types/tapable@*": +"@types/tapable@*", "@types/tapable@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== -"@types/tapable@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.2.tgz#e13182e1b69871a422d7863e11a4a6f5b814a4bd" - integrity sha512-42zEJkBpNfMEAvWR5WlwtTH22oDzcMjFsL9gDGExwF8X8WvAiw7Vwop7hPw03QT8TKfec83LwbHj6SvpqM4ELQ== - "@types/uglify-js@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"