@cloudbase/oauth 0.0.3-alpha.0 → 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,217 +1,217 @@
1
- import {SimpleStorage, RequestFunction} from '../oauth2client/interface';
2
- import {AuthClientRequestOptions} from "../oauth2client/models";
3
- import {defaultStorage} from "../oauth2client/oauth2client";
1
+ import { SimpleStorage, RequestFunction } from '../oauth2client/interface';
2
+ import { AuthClientRequestOptions } from "../oauth2client/models";
3
+ import { defaultStorage } from "../oauth2client/oauth2client";
4
4
 
5
5
  export interface CaptchaOptions {
6
- clientId: string
7
- request: RequestFunction;
8
- storage: SimpleStorage;
9
- // 打开网页并通过URL回调获取 CaptchaToken,针对不通的平台,该函数可以自定义实现, 默认集成浏览器端认证
10
- openURIWithCallback?: OpenURIWithCallbackFuction;
6
+ clientId: string
7
+ request: RequestFunction;
8
+ storage: SimpleStorage;
9
+ // 打开网页并通过URL回调获取 CaptchaToken,针对不通的平台,该函数可以自定义实现, 默认集成浏览器端认证
10
+ openURIWithCallback?: OpenURIWithCallbackFuction;
11
11
  }
12
12
 
13
13
  type OpenURIWithCallbackFuction = (url: string) => Promise<CaptchaToken>;
14
14
 
15
15
  export interface CaptchaToken {
16
- captcha_token: string
17
- expires_in: number
18
- expires_at?: Date | null;
16
+ captcha_token: string
17
+ expires_in: number
18
+ expires_at?: Date | null;
19
19
  }
20
20
 
21
21
  export interface CaptchaRequestOptions extends AuthClientRequestOptions {
22
- withCaptcha?: boolean;
22
+ withCaptcha?: boolean;
23
23
  }
24
24
 
25
25
  export interface GetCaptchaResponse {
26
- captcha_token?: string
27
- expires_in?: number
28
- url?: string
26
+ captcha_token?: string
27
+ expires_in?: number
28
+ url?: string
29
29
  }
30
30
 
31
31
  const GET_CAPTCHA_URL = '/auth/v1/captcha/init'
32
32
 
33
33
  export class Captcha {
34
- private _config: CaptchaOptions;
35
- private _tokenSectionName: string;
34
+ private _config: CaptchaOptions;
35
+ private _tokenSectionName: string;
36
36
 
37
- /**
38
- * constructor
39
- * @param {CaptchaOptions} opts
40
- */
41
- constructor(opts: CaptchaOptions) {
42
- if (!opts.openURIWithCallback) {
43
- opts.openURIWithCallback = this._getDefaultOpenURIWithCallback()
44
- }
45
- if (!opts.storage) {
46
- opts.storage = defaultStorage
47
- }
48
- this._config = opts
49
- this._tokenSectionName = 'captcha_' + opts.clientId
37
+ /**
38
+ * constructor
39
+ * @param {CaptchaOptions} opts
40
+ */
41
+ constructor(opts: CaptchaOptions) {
42
+ if (!opts.openURIWithCallback) {
43
+ opts.openURIWithCallback = this._getDefaultOpenURIWithCallback()
50
44
  }
51
-
52
- /**
53
- * request http like simple fetch api, exp:request('/v1/user/me', {withCredentials:true})
54
- * @param {string} url
55
- * @param {AuthClientRequestOptions} options
56
- */
57
- public async request<T>(
58
- url: string,
59
- options?: CaptchaRequestOptions,
60
- ): Promise<T> {
61
- if (!options) {
62
- options = {};
63
- }
64
- if (!options.method) {
65
- options.method = 'GET'
66
- }
67
- const state = options.method + ":" + url
68
- let reqURL = url;
69
- if (options.withCaptcha) {
70
- reqURL = await this._appendCaptchaTokenToURL(url, state, false);
71
- }
72
- try {
73
- return this._config.request<T>(reqURL, options)
74
- } catch (err) {
75
- if (err.error === 'captcha_required' || err.error === 'captcha_invalid') {
76
- url = await this._appendCaptchaTokenToURL(url, state, err.error === 'captcha_invalid')
77
- return this._config.request<T>(url, options)
78
- } else {
79
- return Promise.reject(err)
80
- }
81
- }
45
+ if (!opts.storage) {
46
+ opts.storage = defaultStorage
82
47
  }
48
+ this._config = opts
49
+ this._tokenSectionName = 'captcha_' + opts.clientId
50
+ }
83
51
 
84
- private _getDefaultOpenURIWithCallback(): OpenURIWithCallbackFuction {
85
- if (window.location.search.indexOf('__captcha') > 0) {
86
- document.body.style.display = 'none';
87
- }
88
- if (document.getElementById('captcha_panel_wrap') === null) {
89
- var elementDiv = document.createElement('div');
90
- elementDiv.style.cssText =
91
- 'background-color: rgba(0, 0, 0, 0.7);position: fixed;left: 0px;right: 0px;top: 0px;bottom: 0px;padding: 9vw 0 0 0;display: none;z-index:100;';
92
- elementDiv.setAttribute('id', 'captcha_panel_wrap');
93
- document.body.appendChild(elementDiv);
94
- }
95
- return this._defaultOpenURIWithCallback
52
+ /**
53
+ * request http like simple fetch api, exp:request('/v1/user/me', {withCredentials:true})
54
+ * @param {string} url
55
+ * @param {AuthClientRequestOptions} options
56
+ */
57
+ public async request<T>(
58
+ url: string,
59
+ options?: CaptchaRequestOptions,
60
+ ): Promise<T> {
61
+ if (!options) {
62
+ options = {};
63
+ }
64
+ if (!options.method) {
65
+ options.method = 'GET'
66
+ }
67
+ const state = options.method + ":" + url
68
+ let reqURL = url;
69
+ if (options.withCaptcha) {
70
+ reqURL = await this._appendCaptchaTokenToURL(url, state, false);
96
71
  }
72
+ try {
73
+ return this._config.request<T>(reqURL, options)
74
+ } catch (err) {
75
+ if (err.error === 'captcha_required' || err.error === 'captcha_invalid') {
76
+ url = await this._appendCaptchaTokenToURL(url, state, err.error === 'captcha_invalid')
77
+ return this._config.request<T>(url, options)
78
+ } else {
79
+ return Promise.reject(err)
80
+ }
81
+ }
82
+ }
97
83
 
98
- /**
99
- * 默认通过浏览器打开网页并获取回调
100
- */
101
- private async _defaultOpenURIWithCallback(url: string): Promise<CaptchaToken> {
102
- const target = document.getElementById('captcha_panel_wrap'),
103
- iframe = document.createElement('iframe')
104
- target.innerHTML = '';
105
- iframe.setAttribute('src', url)
106
- iframe.setAttribute('id', 'review-panel-iframe')
107
- iframe.style.cssText = 'min-width:355px;display:block;height:355px;margin:0 auto;background-color: rgb(255, 255, 255);border: none;';
108
- target.appendChild(iframe);
109
- target.style.display = 'block';
110
- return new Promise<CaptchaToken>((resolve, reject) => {
111
- iframe.onload = function () {
112
- try {
113
- var windowLocation = window.location;
114
- var iframeLocation = iframe.contentWindow.location;
115
- if (
116
- iframeLocation.host +
117
- iframeLocation.pathname ===
118
- windowLocation.host +
119
- windowLocation.pathname
120
- ) {
121
- target.style.display = 'none';
122
- const iframeUrlParams = new URLSearchParams(iframeLocation.search);
123
- const captchToken = iframeUrlParams.get('captcha_token');
124
- if (captchToken) {
125
- return resolve({
126
- captcha_token: captchToken,
127
- expires_in: Number(iframeUrlParams.get('expires_in'))
128
- })
129
- }
130
- return reject({
131
- error: iframeUrlParams.get('error'),
132
- error_description: iframeUrlParams.get('error_description')
133
- })
134
- } else {
135
- target.style.display = 'block';
136
- }
137
- } catch (error) {
138
- target.style.display = 'block';
139
- }
140
- };
141
- })
84
+ private _getDefaultOpenURIWithCallback(): OpenURIWithCallbackFuction {
85
+ if (window.location.search.indexOf('__captcha') > 0) {
86
+ document.body.style.display = 'none';
142
87
  }
143
- /**
144
- * _getCaptchaToken 获取captchaToken
145
- */
146
- private async _getCaptchaToken(forceNewToken: boolean, state: string): Promise<string> {
147
- if (!forceNewToken) {
148
- // 如果本地存在,则直接返回
149
- const captchaToken = await this._findCaptchaToken()
150
- if (captchaToken) {
151
- return captchaToken
152
- }
153
- }
154
- const redirectURL = window.location.origin + window.location.pathname + "?__captcha=on"
155
- const captchaTokenResp = await this._config.request<GetCaptchaResponse>(GET_CAPTCHA_URL, {
156
- method: 'POST',
157
- body: {
158
- client_id: this._config.clientId,
159
- redirect_uri: redirectURL,
160
- state: state
161
- },
162
- withCredentials: false,
163
- })
164
- if (captchaTokenResp.captcha_token) {
165
- const captchaToken = {
166
- captcha_token: captchaTokenResp.captcha_token,
167
- expires_in: captchaTokenResp.expires_in,
168
- }
169
- this._saveCaptchaToken(captchaToken)
170
- return captchaTokenResp.captcha_token
171
- }
172
- const captchaToken = await this._config.openURIWithCallback(captchaTokenResp.url)
173
- this._saveCaptchaToken(captchaToken)
174
- return captchaToken.captcha_token
88
+ if (document.getElementById('captcha_panel_wrap') === null) {
89
+ var elementDiv = document.createElement('div');
90
+ elementDiv.style.cssText =
91
+ 'background-color: rgba(0, 0, 0, 0.7);position: fixed;left: 0px;right: 0px;top: 0px;bottom: 0px;padding: 9vw 0 0 0;display: none;z-index:100;';
92
+ elementDiv.setAttribute('id', 'captcha_panel_wrap');
93
+ document.body.appendChild(elementDiv);
175
94
  }
95
+ return this._defaultOpenURIWithCallback
96
+ }
176
97
 
177
- private async _appendCaptchaTokenToURL(url: string, state: string, forceNewToken: boolean): Promise<string> {
178
- const captchaToken = await this._getCaptchaToken(forceNewToken, state);
179
- if (url.indexOf("?") > 0) {
180
- url += "&captcha_token=" + captchaToken
181
- } else {
182
- url += "?captcha_token=" + captchaToken
98
+ /**
99
+ * 默认通过浏览器打开网页并获取回调
100
+ */
101
+ private async _defaultOpenURIWithCallback(url: string): Promise<CaptchaToken> {
102
+ const target = document.getElementById('captcha_panel_wrap'),
103
+ iframe = document.createElement('iframe')
104
+ target.innerHTML = '';
105
+ iframe.setAttribute('src', url)
106
+ iframe.setAttribute('id', 'review-panel-iframe')
107
+ iframe.style.cssText = 'min-width:355px;display:block;height:355px;margin:0 auto;background-color: rgb(255, 255, 255);border: none;';
108
+ target.appendChild(iframe);
109
+ target.style.display = 'block';
110
+ return new Promise<CaptchaToken>((resolve, reject) => {
111
+ iframe.onload = function () {
112
+ try {
113
+ var windowLocation = window.location;
114
+ var iframeLocation = iframe.contentWindow.location;
115
+ if (
116
+ iframeLocation.host +
117
+ iframeLocation.pathname ===
118
+ windowLocation.host +
119
+ windowLocation.pathname
120
+ ) {
121
+ target.style.display = 'none';
122
+ const iframeUrlParams = new URLSearchParams(iframeLocation.search);
123
+ const captchToken = iframeUrlParams.get('captcha_token');
124
+ if (captchToken) {
125
+ return resolve({
126
+ captcha_token: captchToken,
127
+ expires_in: Number(iframeUrlParams.get('expires_in'))
128
+ })
129
+ }
130
+ return reject({
131
+ error: iframeUrlParams.get('error'),
132
+ error_description: iframeUrlParams.get('error_description')
133
+ })
134
+ } else {
135
+ target.style.display = 'block';
136
+ }
137
+ } catch (error) {
138
+ target.style.display = 'block';
183
139
  }
184
- return url
140
+ };
141
+ })
142
+ }
143
+ /**
144
+ * _getCaptchaToken 获取captchaToken
145
+ */
146
+ private async _getCaptchaToken(forceNewToken: boolean, state: string): Promise<string> {
147
+ if (!forceNewToken) {
148
+ // 如果本地存在,则直接返回
149
+ const captchaToken = await this._findCaptchaToken()
150
+ if (captchaToken) {
151
+ return captchaToken
152
+ }
153
+ }
154
+ const redirectURL = window.location.origin + window.location.pathname + "?__captcha=on"
155
+ const captchaTokenResp = await this._config.request<GetCaptchaResponse>(GET_CAPTCHA_URL, {
156
+ method: 'POST',
157
+ body: {
158
+ client_id: this._config.clientId,
159
+ redirect_uri: redirectURL,
160
+ state: state
161
+ },
162
+ withCredentials: false,
163
+ })
164
+ if (captchaTokenResp.captcha_token) {
165
+ const captchaToken = {
166
+ captcha_token: captchaTokenResp.captcha_token,
167
+ expires_in: captchaTokenResp.expires_in,
168
+ }
169
+ this._saveCaptchaToken(captchaToken)
170
+ return captchaTokenResp.captcha_token
185
171
  }
172
+ const captchaToken = await this._config.openURIWithCallback(captchaTokenResp.url)
173
+ this._saveCaptchaToken(captchaToken)
174
+ return captchaToken.captcha_token
175
+ }
186
176
 
187
- private async _saveCaptchaToken(token: CaptchaToken) {
188
- token.expires_at = new Date(
189
- Date.now() + (token.expires_in - 10) * 1000,
190
- );
191
- const tokenStr: string = JSON.stringify(token);
192
- await this._config.storage.setItem(this._tokenSectionName, tokenStr);
177
+ private async _appendCaptchaTokenToURL(url: string, state: string, forceNewToken: boolean): Promise<string> {
178
+ const captchaToken = await this._getCaptchaToken(forceNewToken, state);
179
+ if (url.indexOf("?") > 0) {
180
+ url += "&captcha_token=" + captchaToken
181
+ } else {
182
+ url += "?captcha_token=" + captchaToken
193
183
  }
184
+ return url
185
+ }
194
186
 
195
- private async _findCaptchaToken(): Promise<string> {
196
- const tokenStr: string = await this._config.storage.getItem(
197
- this._tokenSectionName,
198
- );
199
- if (tokenStr !== undefined && tokenStr !== null) {
200
- try {
201
- const captchaToken = JSON.parse(tokenStr);
202
- if (captchaToken && captchaToken.expires_at) {
203
- captchaToken.expires_at = new Date(captchaToken.expires_at);
204
- }
205
- const isExpired = captchaToken.expires_at < new Date();
206
- if (isExpired) {
207
- return null
208
- }
209
- return captchaToken.captcha_token
210
- } catch (error) {
211
- await this._config.storage.removeItem(this._tokenSectionName);
212
- return null
213
- }
187
+ private async _saveCaptchaToken(token: CaptchaToken) {
188
+ token.expires_at = new Date(
189
+ Date.now() + (token.expires_in - 10) * 1000,
190
+ );
191
+ const tokenStr: string = JSON.stringify(token);
192
+ await this._config.storage.setItem(this._tokenSectionName, tokenStr);
193
+ }
194
+
195
+ private async _findCaptchaToken(): Promise<string> {
196
+ const tokenStr: string = await this._config.storage.getItem(
197
+ this._tokenSectionName,
198
+ );
199
+ if (tokenStr !== undefined && tokenStr !== null) {
200
+ try {
201
+ const captchaToken = JSON.parse(tokenStr);
202
+ if (captchaToken?.expires_at) {
203
+ captchaToken.expires_at = new Date(captchaToken.expires_at);
204
+ }
205
+ const isExpired = captchaToken.expires_at < new Date();
206
+ if (isExpired) {
207
+ return null
214
208
  }
209
+ return captchaToken.captcha_token
210
+ } catch (error) {
211
+ await this._config.storage.removeItem(this._tokenSectionName);
215
212
  return null
213
+ }
216
214
  }
215
+ return null
216
+ }
217
217
  }
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
- export {Syntax, ErrorType} from './oauth2client/consts';
1
+ export { Syntax, ErrorType } from './oauth2client/consts';
2
+
3
+ import { OAuth2Client } from './oauth2client/oauth2client'
2
4
 
3
5
  export {
4
6
  defaultStorage,
@@ -9,8 +11,9 @@ export {
9
11
  OAuth2Client,
10
12
  } from './oauth2client/oauth2client';
11
13
 
12
- export {AuthClient, SimpleStorage} from './oauth2client/interface';
14
+ export { AuthClient, SimpleStorage } from './oauth2client/interface';
13
15
 
16
+ // import { Credentials } from './oauth2client/models'
14
17
  export {
15
18
  Credentials,
16
19
  ResponseError,
@@ -18,7 +21,29 @@ export {
18
21
  AuthClientRequestOptions,
19
22
  } from './oauth2client/models';
20
23
 
21
- export {AuthOptions, Auth} from './auth/apis';
24
+ import { AuthOptions, Auth } from './auth/apis'
25
+
26
+ export { AuthOptions, Auth } from './auth/apis';
22
27
 
23
28
  import * as authModels from './auth/models';
24
- export {authModels};
29
+ export { authModels };
30
+
31
+
32
+ export class CloudbaseOAuth {
33
+ public oauth2client: OAuth2Client
34
+ public authApi: Auth
35
+
36
+ constructor(authOptions: AuthOptions) {
37
+ const { apiOrigin, clientId } = authOptions
38
+ this.oauth2client = new OAuth2Client({
39
+ apiOrigin,
40
+ clientId
41
+ })
42
+
43
+ this.authApi = new Auth({
44
+ credentialsClient: this.oauth2client,
45
+ ...authOptions
46
+ })
47
+ }
48
+ }
49
+
@@ -1,4 +1,4 @@
1
- import {Credentials, AuthClientRequestOptions} from './models';
1
+ import { Credentials, AuthClientRequestOptions } from './models';
2
2
 
3
3
  /**
4
4
  * the interface for the Oauth2Client
@@ -25,20 +25,33 @@ export abstract class AuthClient {
25
25
  abstract getAccessToken(): Promise<string>;
26
26
  }
27
27
 
28
- export type RequestFunction = <T>(url: string,options?: AuthClientRequestOptions) => Promise<T>;
28
+ export type RequestFunction = <T>(url: string, options?: AuthClientRequestOptions) => Promise<T>;
29
29
 
30
30
  /** An interface of the Simple Web Storage API */
31
31
  export interface SimpleStorage {
32
32
  /**
33
33
  * value = storage[key]
34
34
  */
35
- getItem(key: string): Promise<string | null>;
35
+ getItem: (key: string) => Promise<string | null>;
36
36
  /**
37
37
  * delete storage[key]
38
38
  */
39
- removeItem(key: string): Promise<void>;
39
+ removeItem: (key: string) => Promise<void>;
40
40
  /**
41
41
  * storage[key] = value
42
42
  */
43
- setItem(key: string, value: string): Promise<void>;
43
+ setItem: (key: string, value: string) => Promise<void>;
44
+
45
+ /**
46
+ * value = storage[key]
47
+ */
48
+ getItemSync: (key: string) => string | null;
49
+ /**
50
+ * delete storage[key]
51
+ */
52
+ removeItemSync: (key: string) => void;
53
+ /**
54
+ * storage[key] = value
55
+ */
56
+ setItemSync: (key: string, value: string) => void;
44
57
  }