Skip to content

Commit e294ac0

Browse files
committed
Adjust authorization dialog, implement automatic authentication, update openapi spec
1 parent b3afbad commit e294ac0

File tree

3 files changed

+334
-9
lines changed

3 files changed

+334
-9
lines changed

Diff for: emby-auth.js

+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+

2+
function renderAuths() {
3+
return {
4+
wrapComponents: {
5+
auths: (OriginalComponent, system) => (props) => {
6+
7+
const { definitions, getComponent, authSelectors, errSelectors } = props;
8+
const AuthItem = getComponent('AuthItem');
9+
const Oauth2 = getComponent('oauth2', true);
10+
const Button = getComponent('Button');
11+
12+
const authorized = authSelectors.authorized();
13+
14+
const authorizedAuth = definitions.filter((definition, key) => {
15+
return !!authorized.get(key);
16+
});
17+
18+
const nonOauthDefinitions = definitions.filter(
19+
schema => schema.get('type') !== 'oauth2'
20+
);
21+
const oauthDefinitions = definitions.filter(
22+
schema => schema.get('type') === 'oauth2'
23+
);
24+
25+
const httpSchemaDefinitions = definitions.filter(
26+
schema => schema.get('type') === 'http'
27+
);
28+
29+
return system.React.createElement('div', { className: 'auth-container' },
30+
!!nonOauthDefinitions.size
31+
&& system.React.createElement('form', { onSubmit: OriginalComponent.submitAuth },
32+
nonOauthDefinitions.map((schema, name) => {
33+
return system.React.createElement(AuthItem, {
34+
key: name,
35+
schema: schema,
36+
name: name,
37+
getComponent: getComponent,
38+
onAuthChange: OriginalComponent.onAuthChange,
39+
authorized: authorized,
40+
errSelectors: errSelectors
41+
});
42+
})
43+
.toArray(),
44+
45+
!httpSchemaDefinitions.size && system.React.createElement('div', { className: 'auth-btn-wrapper' },
46+
nonOauthDefinitions.size === authorizedAuth.size
47+
? system.React.createElement(Button,
48+
{
49+
className: 'btn modal-btn auth',
50+
onClick: OriginalComponent.logoutClick
51+
},
52+
'Logout'
53+
)
54+
: system.React.createElement(Button,
55+
{ type: 'submit', className: 'btn modal-btn auth authorize' },
56+
'Authorize'
57+
),
58+
system.React.createElement(Button,
59+
{ className: 'btn modal-btn auth btn-done', onClick: OriginalComponent.close },
60+
'Close'
61+
)
62+
)
63+
),
64+
oauthDefinitions && oauthDefinitions.size
65+
? system.React.createElement('div', null,
66+
system.React.createElement('div', { className: 'scope-def' },
67+
system.React.createElement('p', null,
68+
'Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.'
69+
),
70+
system.React.createElement('p', null,
71+
'API requires the following scopes. Select which ones you want to grant to Swagger UI.'
72+
)
73+
),
74+
definitions
75+
.filter(schema => schema.get('type') === 'oauth2')
76+
.map((schema, name) => {
77+
return system.React.createElement('div',
78+
{ key: name },
79+
system.React.createElement(Oauth2, {
80+
authorized: authorized,
81+
schema: schema,
82+
name: name
83+
})
84+
);
85+
})
86+
.toArray()
87+
)
88+
: null
89+
);
90+
}
91+
}
92+
};
93+
};
94+
95+
96+
function renderHttpAuth() {
97+
return {
98+
wrapComponents: {
99+
HttpAuth: (OriginalComponent, system) => (props) => {
100+
101+
let { schema, getComponent, errSelectors, name } = props;
102+
103+
const Input = getComponent('Input');
104+
const Row = getComponent('Row');
105+
const Col = getComponent('Col');
106+
const AuthError = getComponent('authError');
107+
const Markdown = getComponent('Markdown');
108+
const JumpToPath = getComponent('JumpToPath', true);
109+
110+
const scheme = (schema.get('scheme') || '').toLowerCase();
111+
let value = null; // props.getValue();
112+
let errors = errSelectors
113+
.allErrors()
114+
.filter(err => err.get('authId') === name);
115+
116+
if (scheme === 'basic') {
117+
let username = value ? value.get('username') : null;
118+
return system.React.createElement('div', null,
119+
system.React.createElement('h4', null, system.React.createElement('code', null, name || schema.get('name')),
120+
'\xA0 (http, Basic)',
121+
system.React.createElement(JumpToPath,
122+
{
123+
path: ['securityDefinitions', name]
124+
})
125+
),
126+
username && system.React.createElement('h6', null, 'Authorized'),
127+
system.React.createElement(Row, null,
128+
system.React.createElement(Markdown, { source: schema.get('description') })
129+
),
130+
system.React.createElement(Row, null,
131+
system.React.createElement('label', null, 'Username:'),
132+
username
133+
? system.React.createElement('code', null, ' ', username, ' ')
134+
: system.React.createElement(Col, null,
135+
system.React.createElement(Input,
136+
{
137+
type: 'text',
138+
required: 'required',
139+
name: 'username',
140+
onChange: onChange
141+
})
142+
)
143+
),
144+
system.React.createElement(Row, null,
145+
system.React.createElement('label', null, 'Password:'),
146+
username
147+
? system.React.createElement('code', null, ' ****** ')
148+
: system.React.createElement(Col, null,
149+
system.React.createElement(Input,
150+
{
151+
required: 'required',
152+
autoComplete: 'new-password',
153+
name: 'password',
154+
type: 'password',
155+
onChange: onChange
156+
})
157+
)
158+
),
159+
errors.valueSeq().map((error, key) => {
160+
return system.React.createElement(AuthError,
161+
{
162+
error: error,
163+
key: key
164+
});
165+
})
166+
);
167+
}
168+
169+
if (scheme === 'bearer') {
170+
return system.React.createElement('div', null,
171+
system.React.createElement('h4', null,
172+
system.React.createElement('code', null, name || schema.get('name')),
173+
'\xA0 (http, Emby)',
174+
system.React.createElement(JumpToPath,
175+
{
176+
path: ['securityDefinitions', name]
177+
})
178+
),
179+
value && system.React.createElement('h6', null, 'Authorized'),
180+
//system.React.createElement(Row, null,
181+
// system.React.createElement('p', null, 'Authorize-Format: ',
182+
183+
// system.React.createElement('span', null, schema.get('bearerFormat')))
184+
//),
185+
system.React.createElement(Row, null,
186+
system.React.createElement(Markdown, { source: schema.get('description') })
187+
),
188+
//system.React.createElement(Row, null,
189+
// system.React.createElement('label', null, 'Value:'),
190+
// value
191+
// ? system.React.createElement('code', null, ' ****** ')
192+
// : system.React.createElement(Col, null,
193+
// system.React.createElement(Input,
194+
// {
195+
// type: 'text',
196+
// onChange: onChange
197+
// })
198+
// )
199+
//),
200+
errors.valueSeq().map((error, key) => {
201+
return system.React.createElement(AuthError,
202+
{
203+
error: error,
204+
key: key
205+
});
206+
})
207+
);
208+
}
209+
return system.React.createElement('div', null,
210+
system.React.createElement('em', null,
211+
system.React.createElement('b', null, name),
212+
' HTTP authentication: unsupported scheme ',
213+
`'${scheme}'`
214+
)
215+
);
216+
}
217+
}
218+
};
219+
};
220+

Diff for: index.html

+41-6
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@
3636
<script src="./swagger-ui-bundle.js"></script>
3737
<script src="./swagger-ui-standalone-preset.js"></script>
3838
<script src="./emby-custom.js"></script>
39+
<script src="./emby-auth.js"></script>
3940

4041
<script>
41-
window.onload = function () {
42+
window.onload = function() {
4243

4344
function getWindowLocationSearch(win) {
4445
'use strict';
@@ -70,6 +71,30 @@
7071
return decodeURIComponent(results[1].replace(/\+/g, " "));
7172
}
7273

74+
function preauthorizeApiKey(system, key, value) {
75+
const {
76+
authActions: { authorize },
77+
specSelectors: { specJson, isOAS3 }
78+
} = system;
79+
80+
const definitionBase = isOAS3() ? ["components", "securitySchemes"] : ["securityDefinitions"];
81+
82+
const schema = specJson().getIn([...definitionBase, key]);
83+
84+
if(!schema) {
85+
return null;
86+
}
87+
88+
return authorize({
89+
[key]: {
90+
value,
91+
schema: schema.toJS()
92+
}
93+
});
94+
}
95+
96+
var apikey = getParameterByName('api_key');
97+
7398
// Create Configuration
7499
const config = {
75100
url: getParameterByName('url') || "http://localhost:8096/openapi",
@@ -89,17 +114,27 @@
89114
caseInsensitivePhraseFilter,
90115
renderPrimitive,
91116
renderEnum,
92-
renderArray
117+
renderArray,
118+
renderHttpAuth,
119+
renderAuths
93120
],
94-
layout: 'StandaloneLayout'
95-
};
121+
layout: 'StandaloneLayout',
122+
onComplete: function() {
123+
if (apikey && apikey.trim() !== '') {
124+
preauthorizeApiKey(ui, 'apikeyauth', apikey);
125+
}
126+
}
127+
}
96128

97129
if (getParameterByName('staticview')) {
98130

99-
config.plugins = [caseInsensitivePhraseFilter, disableAuthorizePlugin, hideTopbarPlugin,
100-
renderPrimitive, renderEnum, renderArray];
131+
config.plugins = [
132+
caseInsensitivePhraseFilter, disableAuthorizePlugin, hideTopbarPlugin,
133+
renderPrimitive, renderEnum, renderArray
134+
];
101135
config.url = 'openapi.json';
102136
config.supportedSubmitMethods = [];
137+
apikey = null;
103138
}
104139

105140
// Build a system

0 commit comments

Comments
 (0)