@vtecx/vtecxnext 1.0.4 → 1.0.5

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.
@@ -695,6 +695,18 @@ export declare const addalias: (req: IncomingMessage, res: ServerResponse, feed:
695
695
  * @return message
696
696
  */
697
697
  export declare const removealias: (req: IncomingMessage, res: ServerResponse, feed: any) => Promise<any>;
698
+ /**
699
+ * OAuth authorization request to LINE
700
+ * @param req request (for authentication)
701
+ * @param res response (for authentication)
702
+ */
703
+ export declare const oauthLine: (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
704
+ /**
705
+ * OAuth authorization request to LINE
706
+ * @param req request (for authentication)
707
+ * @param res response (for authentication)
708
+ */
709
+ export declare const oauthCallbackLine: (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
698
710
  /**
699
711
  * Error returned from vte.cx
700
712
  */
package/dist/vtecxnext.js CHANGED
@@ -1,13 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.deleteSignature = exports.putSignatures = exports.putSignature = exports.toPdf = exports.getBQCsv = exports.getBQ = exports.deleteBQ = exports.postBQ = exports.getPage = exports.pagination = exports.getSessionLong = exports.getSessionString = exports.getSessionEntry = exports.getSessionFeed = exports.deleteSessionLong = exports.deleteSessionString = exports.deleteSessionEntry = exports.deleteSessionFeed = exports.incrementSession = exports.setSessionLong = exports.setSessionString = exports.setSessionEntry = exports.setSessionFeed = exports.getRangeids = exports.rangeids = exports.setids = exports.getids = exports.addids = exports.allocids = exports.deleteFolder = exports.deleteEntry = exports.put = exports.post = exports.count = exports.getFeed = exports.getEntry = exports.log = exports.rxid = exports.service = exports.isLoggedin = exports.whoami = exports.account = exports.uid = exports.now = exports.logout = exports.loginWithRxid = exports.login = exports.sendMessage = exports.checkXRequestedWith = exports.hello = void 0;
7
- exports.VtecxNextError = exports.removealias = exports.addalias = exports.removeacl = exports.addacl = exports.getcontent = exports.deletecontent = exports.putcontent = exports.savefiles = exports.deleteusers = exports.deleteuser = exports.canceluser = exports.activateusers = exports.activateuser = exports.revokeusers = exports.revokeuser = exports.userstatus = exports.changeaccount_verify = exports.changeaccount = exports.changepassByAdmin = exports.changepass = exports.passreset = exports.adduserByAdmin = exports.adduser = exports.noGroupMember = exports.leaveGroup = exports.joinGroup = exports.getMessageQueue = exports.setMessageQueue = exports.setMessageQueueStatus = exports.pushNotification = exports.sendMail = exports.checkSignature = void 0;
30
+ exports.VtecxNextError = exports.oauthCallbackLine = exports.oauthLine = exports.removealias = exports.addalias = exports.removeacl = exports.addacl = exports.getcontent = exports.deletecontent = exports.putcontent = exports.savefiles = exports.deleteusers = exports.deleteuser = exports.canceluser = exports.activateusers = exports.activateuser = exports.revokeusers = exports.revokeuser = exports.userstatus = exports.changeaccount_verify = exports.changeaccount = exports.changepassByAdmin = exports.changepass = exports.passreset = exports.adduserByAdmin = exports.adduser = exports.noGroupMember = exports.leaveGroup = exports.joinGroup = exports.getMessageQueue = exports.setMessageQueue = exports.setMessageQueueStatus = exports.pushNotification = exports.sendMail = exports.checkSignature = void 0;
8
31
  const sqlstring_1 = __importDefault(require("sqlstring"));
9
32
  const formidable_1 = __importDefault(require("formidable"));
10
33
  const fs_1 = __importDefault(require("fs"));
34
+ const url_1 = __importStar(require("url"));
11
35
  /**
12
36
  * Hello world.
13
37
  */
@@ -66,7 +90,7 @@ const login = async (req, res, wsse, reCaptchaToken) => {
66
90
  const url = `/d/?_login${param}`;
67
91
  const headers = { 'X-WSSE': `${wsse}` };
68
92
  const response = await fetchVtecx(method, url, headers);
69
- const feed = await response.json();
93
+ //const feed = await response.json()
70
94
  // vte.cxからのset-cookieを転記
71
95
  setCookie(response, res);
72
96
  // レスポンスのエラーチェック
@@ -2185,6 +2209,34 @@ const removealias = async (req, res, feed) => {
2185
2209
  return await getJson(response);
2186
2210
  };
2187
2211
  exports.removealias = removealias;
2212
+ /**
2213
+ * OAuth authorization request to LINE
2214
+ * @param req request (for authentication)
2215
+ * @param res response (for authentication)
2216
+ */
2217
+ const oauthLine = async (req, res) => {
2218
+ const provider = 'line';
2219
+ const oauthUrl = 'https://access.line.me/oauth2/v2.1/authorize';
2220
+ return await oauth(req, res, provider, oauthUrl);
2221
+ };
2222
+ exports.oauthLine = oauthLine;
2223
+ /**
2224
+ * OAuth authorization request to LINE
2225
+ * @param req request (for authentication)
2226
+ * @param res response (for authentication)
2227
+ */
2228
+ const oauthCallbackLine = async (req, res) => {
2229
+ // OAuthアクセストークン、OAuth情報を取得
2230
+ const provider = 'line';
2231
+ const accesstokenUrl = 'https://api.line.me/oauth2/v2.1/token';
2232
+ const oauthInfo = await oauthGetAccesstoken(req, res, provider, accesstokenUrl);
2233
+ // ユーザ識別情報を取得
2234
+ const userInfo = await oauthGetUserinfoLine(req, res, oauthInfo);
2235
+ // vte.cxユーザと連携・ログイン
2236
+ await oauthLink(req, res, provider, userInfo);
2237
+ return true;
2238
+ };
2239
+ exports.oauthCallbackLine = oauthCallbackLine;
2188
2240
  //---------------------------------------------
2189
2241
  /**
2190
2242
  * Error returned from vte.cx
@@ -2205,10 +2257,12 @@ exports.VtecxNextError = VtecxNextError;
2205
2257
  * @param url サーブレットパス以降のURL
2206
2258
  * @param req リクエスト。認証情報設定に使用。
2207
2259
  * @param body リクエストデータ
2260
+ * @param additionalHeaders リクエストヘッダ追加分
2208
2261
  * @param targetService 連携サービス名
2262
+ * @param mode RequestMode ("cors" | "navigate" | "no-cors" | "same-origin")
2209
2263
  * @returns promise
2210
2264
  */
2211
- const requestVtecx = async (method, url, req, body, additionalHeaders, targetService) => {
2265
+ const requestVtecx = async (method, url, req, body, additionalHeaders, targetService, mode) => {
2212
2266
  // cookieの値をvte.cxへのリクエストヘッダに設定
2213
2267
  const cookie = req ? req.headers['cookie'] : undefined;
2214
2268
  const headers = cookie ? { 'Cookie': cookie } : {};
@@ -2226,7 +2280,7 @@ const requestVtecx = async (method, url, req, body, additionalHeaders, targetSer
2226
2280
  headers['X-SERVICEKEY'] = servicekey;
2227
2281
  }
2228
2282
  }
2229
- return fetchVtecx(method, url, headers, body);
2283
+ return fetchVtecx(method, url, headers, body, mode);
2230
2284
  };
2231
2285
  /**
2232
2286
  * vte.cxへリクエスト
@@ -2234,9 +2288,10 @@ const requestVtecx = async (method, url, req, body, additionalHeaders, targetSer
2234
2288
  * @param url サーブレットパス以降のURL
2235
2289
  * @param headers リクエストヘッダ。連想配列で指定。
2236
2290
  * @param body リクエストデータ
2291
+ * @param mode RequestMode ("cors" | "navigate" | "no-cors" | "same-origin")
2237
2292
  * @returns promise
2238
2293
  */
2239
- const fetchVtecx = async (method, url, headers, body) => {
2294
+ const fetchVtecx = async (method, url, headers, body, mode) => {
2240
2295
  //console.log(`[vtecxnext fetchVtecx] url=${process.env.VTECX_URL}${url}`)
2241
2296
  headers['X-Requested-With'] = 'XMLHttpRequest';
2242
2297
  const apiKey = process.env.VTECX_APIKEY;
@@ -2248,6 +2303,9 @@ const fetchVtecx = async (method, url, headers, body) => {
2248
2303
  method: method,
2249
2304
  headers: headers
2250
2305
  };
2306
+ if (mode) {
2307
+ requestInit['mode'] = mode;
2308
+ }
2251
2309
  return fetch(`${process.env.VTECX_URL}${url}`, requestInit);
2252
2310
  };
2253
2311
  /**
@@ -2261,6 +2319,21 @@ const setCookie = (response, res) => {
2261
2319
  res.setHeader('set-cookie', setCookieVal);
2262
2320
  }
2263
2321
  };
2322
+ /**
2323
+ * vte.cxからのallow-originを、ブラウザへレスポンスする。
2324
+ * @param response vte.cxからのレスポンス
2325
+ * @param res ブラウザへのレスポンス
2326
+ */
2327
+ const setAllowOrigin = (response, res) => {
2328
+ let val = response.headers.get('access-control-allow-origin');
2329
+ val ? res.setHeader('access-control-allow-origin', val) : '';
2330
+ val = response.headers.get('access-control-allow-methods');
2331
+ val ? res.setHeader('access-control-allow-methods', val) : '';
2332
+ val = response.headers.get('access-control-allow-headers');
2333
+ val ? res.setHeader('access-control-allow-headers', val) : '';
2334
+ val = response.headers.get('access-control-allow-credentials');
2335
+ val ? res.setHeader('access-control-allow-credentials', val) : '';
2336
+ };
2264
2337
  /**
2265
2338
  * vte.cxからのレスポンスヘッダを、ブラウザへレスポンスする。
2266
2339
  * コンテンツの戻し時に使用。
@@ -2429,3 +2502,217 @@ const buffer = async (readable) => {
2429
2502
  }
2430
2503
  return Buffer.concat(chunks);
2431
2504
  };
2505
+ /**
2506
+ * OAuth authorization request
2507
+ * @param req request (for authentication)
2508
+ * @param res response (for authentication)
2509
+ * @param provider OAuth provider name
2510
+ * @param oauthUrl OAuth authorization request url
2511
+ * @return true
2512
+ */
2513
+ const oauth = async (req, res, provider, oauthUrl) => {
2514
+ //console.log(`[vtecxnext oauth] start. provider=${provider} oauthUrl=${oauthUrl}`)
2515
+ // TODO reCAPTCHAを必須とすべき。
2516
+ // 入力チェック
2517
+ checkNotNull(provider, 'OAuth provider');
2518
+ // vte.cxへリクエスト (state取得)
2519
+ const method = 'POST';
2520
+ const url = `/o/${provider}/create_state`;
2521
+ const response = await requestVtecx(method, url, req);
2522
+ // レスポンスのエラーチェック
2523
+ await checkVtecxResponse(response);
2524
+ // 戻り値
2525
+ const data = await getJson(response);
2526
+ // state生成
2527
+ if (!data || !data.feed || !data.feed.title) {
2528
+ throw new VtecxNextError(401, `Could not generate state.`);
2529
+ }
2530
+ //console.log(`[vtecxnext oauth] response data=${JSON.stringify(data)}`)
2531
+ const state = data.feed.title;
2532
+ const client_id = data.feed.subtitle;
2533
+ const redirect_uri = data.feed.link[0].___href;
2534
+ const origin = getOrigin(oauthUrl);
2535
+ // 認可リクエストリダイレクトURL生成
2536
+ //console.log(`[vtecxnext oauth] redirect_uri=${redirect_uri}`)
2537
+ //console.log(`[vtecxnext oauth] origin=${origin}`)
2538
+ const authorizationUrl = `${oauthUrl}?response_type=code&client_id=${client_id}&redirect_uri=${encodeURI(redirect_uri)}&state=${state}&scope=profile`;
2539
+ //console.log(`[vtecxnext oauth] authorizationUrl=${authorizationUrl}`)
2540
+ res.setHeader('Location', authorizationUrl);
2541
+ //res.setHeader('Access-Control-Allow-Origin', origin)
2542
+ //res.setHeader('Access-Control-Allow-Method', 'GET, OPTIONS')
2543
+ //console.log(`[vtecxnext oauth] response headers=${JSON.stringify(res.getHeaders())}`)
2544
+ res.writeHead(302);
2545
+ res.end();
2546
+ return true;
2547
+ };
2548
+ /**
2549
+ * OAuth authorization request
2550
+ * @param req request (for authentication)
2551
+ * @param res response (for authentication)
2552
+ * @param provider OAuth provider name
2553
+ * @param oauthUrl OAuth get accesstoken request url
2554
+ * @return {'client_id', 'client_secret', 'redirect_uri', 'state', 'access_token'}
2555
+ */
2556
+ const oauthGetAccesstoken = async (req, res, provider, accesstokenUrl) => {
2557
+ //console.log(`[vtecxnext oauthGetAccesstoken] start. provider=${provider} oauthUrl=${accesstokenUrl}`)
2558
+ // stateチェック
2559
+ const parseUrl = url_1.default.parse(req.url ? req.url : '', true);
2560
+ const state = parseUrl.query.state;
2561
+ const code = parseUrl.query.code;
2562
+ if (!state) {
2563
+ throw new VtecxNextError(401, `Could not get state on redirect.`);
2564
+ }
2565
+ if (!code) {
2566
+ throw new VtecxNextError(401, `Could not get code on redirect.`);
2567
+ }
2568
+ // vte.cxへリクエスト (stateチェック)
2569
+ const vtecxMethod = 'POST';
2570
+ const vtecxUrl = `/o/${provider}/check_state?state=${state}`;
2571
+ //console.log(`[vtecxnext oauthGetAccesstoken] vtecxUrl=${vtecxUrl}`)
2572
+ const vtecxResponse = await requestVtecx(vtecxMethod, vtecxUrl, req);
2573
+ //console.log(`[vtecxnext oauthGetAccesstoken] check_state response status=${vtecxResponse.status}`)
2574
+ // vte.cxからのset-cookieを転記
2575
+ setCookie(vtecxResponse, res);
2576
+ // レスポンスのエラーチェック
2577
+ await checkVtecxResponse(vtecxResponse);
2578
+ // 戻り値
2579
+ const data = await getJson(vtecxResponse);
2580
+ // stateチェック
2581
+ if (!data || !data.feed || !data.feed.title) {
2582
+ throw new VtecxNextError(401, `Invalid state.`);
2583
+ }
2584
+ const client_id = data.feed.subtitle;
2585
+ const client_secret = data.feed.rights;
2586
+ const redirect_uri = data.feed.link[0].___href;
2587
+ //console.log(`[vtecxnext oauthGetAccesstoken] client_id=${client_id}`)
2588
+ //console.log(`[vtecxnext oauthGetAccesstoken] client_secret=${client_secret}`)
2589
+ //console.log(`[vtecxnext oauthGetAccesstoken] redirect_uri=${redirect_uri}`)
2590
+ const encodeRedirect_uri = encodeURIComponent(redirect_uri);
2591
+ //console.log(`[vtecxnext oauthGetAccesstoken] encode redirect_uri=${encodeRedirect_uri}`)
2592
+ // アクセストークン取得URL生成
2593
+ const accesstokenMethod = 'POST';
2594
+ const accessTokenData = {
2595
+ 'grant_type': 'authorization_code',
2596
+ 'code': code,
2597
+ 'redirect_uri': redirect_uri,
2598
+ 'client_id': client_id,
2599
+ 'client_secret': client_secret
2600
+ };
2601
+ const accesstokenBody = createURLSearchParams(accessTokenData);
2602
+ //const accesstokenBodyStr = `grant_type=authorization_code&code=${code}&redirect_uri=${encodeRedirect_uri}&client_id=${client_id}&client_secret=${client_secret}`
2603
+ //console.log(`[vtecxnext oauthGetAccesstoken] accesstokenUrl=${accesstokenUrl}`)
2604
+ //console.log(`[vtecxnext oauthGetAccesstoken] accesstokenBodyStr=${accesstokenBodyStr}`)
2605
+ //const accesstokenBody = Buffer.from(accesstokenBodyStr, 'utf-8')
2606
+ const requestInit = {
2607
+ body: accesstokenBody,
2608
+ method: accesstokenMethod
2609
+ };
2610
+ const accesstokenResponse = await fetch(accesstokenUrl, requestInit);
2611
+ if (accesstokenResponse.status !== 200) {
2612
+ const errorInfo = await accesstokenResponse.json();
2613
+ //console.log(`[vtecxnext oauthGetAccesstoken] Get accesstoken failed. ${JSON.stringify(errorInfo)}`)
2614
+ const errMsg = `${'error' in errorInfo ? errorInfo.error + '. ' : ''} ${'error_description' in errorInfo ? errorInfo.error_description : ''}`;
2615
+ throw new VtecxNextError(401, `Get accesstoken failed. status=${accesstokenResponse.status} ${errMsg}`);
2616
+ }
2617
+ const accesstokenInfo = await accesstokenResponse.json();
2618
+ const access_token = accesstokenInfo.access_token;
2619
+ if (!access_token) {
2620
+ throw new VtecxNextError(401, `Get accesstoken failed.`);
2621
+ }
2622
+ return {
2623
+ 'client_id': client_id,
2624
+ 'client_secret': client_secret,
2625
+ 'redirect_uri': redirect_uri,
2626
+ 'state': state,
2627
+ 'access_token': access_token
2628
+ };
2629
+ };
2630
+ /**
2631
+ * OAuth get userinfo request
2632
+ * @param req request (for authentication)
2633
+ * @param res response (for authentication)
2634
+ * @param oauthInfo OAuth info {'client_id', 'client_secret', 'redirect_uri', 'state', 'access_token'}
2635
+ * @return userinfo {'guid', 'nickname', 'state'}
2636
+ */
2637
+ const oauthGetUserinfoLine = async (req, res, oauthInfo) => {
2638
+ //console.log(`[vtecxnext oauthGetUserinfoLine] start. oauthInfo=${JSON.stringify(oauthInfo)}`)
2639
+ // LINEユーザ識別情報取得リクエスト
2640
+ const url = 'https://api.line.me/v2/profile';
2641
+ const method = 'GET';
2642
+ const headers = { 'Authorization': `Bearer ${oauthInfo.access_token}` };
2643
+ //console.log(`[vtecxnext oauthGetUserinfoLine] url=${url}`)
2644
+ const requestInit = {
2645
+ headers: headers,
2646
+ method: method
2647
+ };
2648
+ const response = await fetch(url, requestInit);
2649
+ if (response.status !== 200) {
2650
+ throw new VtecxNextError(401, `Get user information failed. status=${response.status}`);
2651
+ }
2652
+ const userInfo = await response.json();
2653
+ const guid = 'userId' in userInfo ? userInfo.userId : undefined;
2654
+ const nickname = 'displayName' in userInfo ? userInfo.displayName : '';
2655
+ if (!guid) {
2656
+ throw new VtecxNextError(401, `Get user information failed. `);
2657
+ }
2658
+ return {
2659
+ 'guid': guid,
2660
+ 'nickname': nickname,
2661
+ 'state': oauthInfo.state
2662
+ };
2663
+ };
2664
+ /**
2665
+ * OAuth user link.
2666
+ * @param req request
2667
+ * @param res response
2668
+ * @param provider OAuth provider name
2669
+ * @param userInfo user info
2670
+ * @return true if log in has been successful.
2671
+ */
2672
+ const oauthLink = async (req, res, provider, userInfo) => {
2673
+ //console.log(`[vtecxnext oauthLink] start. userInfo=${JSON.stringify(userInfo)}`)
2674
+ // OAuthリンク・ログイン
2675
+ // reCAPTCHA tokenは任意
2676
+ //const param = reCaptchaToken ? `&g-recaptcha-token=${reCaptchaToken}` : ''
2677
+ const param = '';
2678
+ const method = 'POST';
2679
+ const url = `/o/${provider}/link?state=${userInfo.state}${param}`;
2680
+ const reqFeed = [{ 'title': userInfo.guid, 'subtitle': userInfo.nickname }];
2681
+ const response = await fetchVtecx(method, url, {}, JSON.stringify(reqFeed));
2682
+ const feed = await response.json();
2683
+ // vte.cxからのset-cookieを転記
2684
+ setCookie(response, res);
2685
+ // レスポンスのエラーチェック
2686
+ let isLoggedin;
2687
+ if (response.status < 400) {
2688
+ isLoggedin = true;
2689
+ }
2690
+ else {
2691
+ isLoggedin = false;
2692
+ }
2693
+ //console.log(`[vtecxnext oauthLink] end. status=${response.status} message=${feed.feed.title}`)
2694
+ return isLoggedin;
2695
+ };
2696
+ /**
2697
+ * URLからOriginを取得
2698
+ * @param oauthUrl URL
2699
+ * @returns Origin
2700
+ */
2701
+ const getOrigin = (oauthUrl) => {
2702
+ const tmpIdx = oauthUrl.indexOf('://') + 3;
2703
+ let idx = oauthUrl.indexOf('/', tmpIdx);
2704
+ if (idx < 0) {
2705
+ idx = oauthUrl.length;
2706
+ }
2707
+ return oauthUrl.substring(0, idx);
2708
+ };
2709
+ /**
2710
+ * URLSearchParamsを生成.
2711
+ * @param data JSON
2712
+ * @returns URLSearchParams
2713
+ */
2714
+ const createURLSearchParams = (data) => {
2715
+ const params = new url_1.URLSearchParams();
2716
+ Object.keys(data).forEach(key => params.append(key, data[key]));
2717
+ return params;
2718
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtecx/vtecxnext",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "vte.cx Next.js api",
5
5
  "main": "dist/index.js",
6
6
  "files": [