junggilpark 1 год назад
Родитель
Сommit
0148b63962
11 измененных файлов с 208 добавлено и 550 удалено
  1. BIN
      appPackage.zip
  2. 26 0
      package-lock.json
  3. 2 0
      package.json
  4. 179 147
      src/app.js
  5. 0 274
      src/auth/AuthProvider.js
  6. 0 40
      src/authConfig.js
  7. 0 31
      src/routes/auth.js
  8. 0 17
      src/routes/index.js
  9. 0 41
      src/routes/users.js
  10. 1 0
      src/views/hello.html
  11. BIN
      test - 복사본 (3).xlsx

BIN
appPackage.zip


+ 26 - 0
package-lock.json

@@ -13,6 +13,7 @@
                 "@azure/msal-node": "^2.8.1",
                 "@microsoft/microsoft-graph-client": "^3.0.7",
                 "@microsoft/teams-js": "^2.21.0",
+                "@supercharge/promise-pool": "^3.2.0",
                 "archiver": "^7.0.1",
                 "axios": "^1.6.8",
                 "cookie-parser": "^1.4.6",
@@ -35,6 +36,7 @@
                 "pptxgenjs": "^3.12.0",
                 "restify": "^11.1.0",
                 "send": "^0.18.0",
+                "stream": "^0.0.2",
                 "unzipper": "^0.11.4",
                 "uuid": "^9.0.1",
                 "websocket": "^1.0.35",
@@ -493,6 +495,14 @@
                 "node": ">=14"
             }
         },
+        "node_modules/@supercharge/promise-pool": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/@supercharge/promise-pool/-/promise-pool-3.2.0.tgz",
+            "integrity": "sha512-pj0cAALblTZBPtMltWOlZTQSLT07jIaFNeM8TWoJD1cQMgDB9mcMlVMoetiB35OzNJpqQ2b+QEtwiR9f20mADg==",
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/@tediousjs/connection-string": {
             "version": "0.5.0",
             "resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.5.0.tgz",
@@ -1555,6 +1565,14 @@
             "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
             "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
         },
+        "node_modules/emitter-component": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.2.tgz",
+            "integrity": "sha512-QdXO3nXOzZB4pAjM0n6ZE+R9/+kPpECA/XSELIcc54NeYVnBqIk+4DFiBgK+8QbV3mdvTG6nedl7dTYgO+5wDw==",
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
         "node_modules/emoji-regex": {
             "version": "9.2.2",
             "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
@@ -4774,6 +4792,14 @@
                 "npm": ">=6"
             }
         },
+        "node_modules/stream": {
+            "version": "0.0.2",
+            "resolved": "https://registry.npmjs.org/stream/-/stream-0.0.2.tgz",
+            "integrity": "sha512-gCq3NDI2P35B2n6t76YJuOp7d6cN/C7Rt0577l91wllh0sY9ZBuw9KaSGqH/b0hzn3CWWJbpbW0W0WvQ1H/Q7g==",
+            "dependencies": {
+                "emitter-component": "^1.1.1"
+            }
+        },
         "node_modules/stream-transform": {
             "version": "3.3.1",
             "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-3.3.1.tgz",

+ 2 - 0
package.json

@@ -11,6 +11,7 @@
         "@azure/msal-node": "^2.8.1",
         "@microsoft/microsoft-graph-client": "^3.0.7",
         "@microsoft/teams-js": "^2.21.0",
+        "@supercharge/promise-pool": "^3.2.0",
         "archiver": "^7.0.1",
         "axios": "^1.6.8",
         "cookie-parser": "^1.4.6",
@@ -33,6 +34,7 @@
         "pptxgenjs": "^3.12.0",
         "restify": "^11.1.0",
         "send": "^0.18.0",
+        "stream": "^0.0.2",
         "unzipper": "^0.11.4",
         "uuid": "^9.0.1",
         "websocket": "^1.0.35",

+ 179 - 147
src/app.js

@@ -6,7 +6,6 @@ const express = require("express");
 const axios = require("axios");
 // const SERVER_PORT = process.env.port || process.env.PORT || 53000;
 const SERVER_PORT = process.env.port || process.env.PORT || 53000;
-// const authProvider = require('./auth/AuthProvider');
 const {getFetch, updateFetch} = require('./fetch');
 const bodyParser = require('body-parser');
 const https = require('https');
@@ -18,7 +17,7 @@ const multer  = require('multer');
 // const pptxgen = require('pptxgenjs');
 const msal = require('@azure/msal-node');
 // const FormData = require("form-data");
-// const { v4: uuidv4 } = require('uuid');
+const { v4: uuidv4 } = require('uuid');
 const mime = require('mime-types');
 const {init} = require('./ext.js');
 const BadRequest = require('./error/badRequest.js');
@@ -473,6 +472,8 @@ async function uploadDrive(options, folder, siteId, path) {
 serverApp.post('/api/upload', upload.array('file'),
   errorHandler(async (req, res, next)=>{
     const startTime = new Date();
+    console.log('*** 파일 Upload Start: ' + startTime.toLocaleString());
+
     const files = req.files;
     let {siteId, path, folder, file_path} = req.body; 
     
@@ -486,10 +487,11 @@ serverApp.post('/api/upload', upload.array('file'),
         }
 
         let fileWriteTime = new Date();
+        const nameArray = [];
         if (files && files.length > 0) {
             const promiseArray = [];
             const labelPromiseArray = [];
-            // const fileWriteArray = [];
+            const fileWriteArray = [];
             const possibleExt = POSSIBLE_EXT;
             const {supported_file_ext, protected_file_ext} = possibleExt;
             let supportedArr = [];
@@ -501,158 +503,195 @@ serverApp.post('/api/upload', upload.array('file'),
             }
             let beforeUri = '';
             let beforeItemId = '';
-            for (let idx in files) {
-              const file = files[idx];
+            const now = new Date();
+            console.log('File Write Start : ', now.toLocaleString());
+            const promiseArrNew = files.map((file, idx)=>{
               file.originalname = Buffer.from(file.originalname, 'ascii').toString('utf8');
               let originName = file.originalname;
               if (originName) {
-                  let ext = globalPath.extname(originName);
-                  if (supportedArr.length > 0 && !supportedArr.includes(ext)) {
-                      return res.json({success:'F', message: '파일명 : ' + originName 
-                                        +'<br>업로드 불가 파일이 포함되어 있습니다.<br>가능 확장자 :' 
-                                        + JSON.stringify(supportedArr)});
-                  }
-
-                  // const uuid = uuidv4();
-                  // const realFileName = uuid + ext;
-                  // fileWriteArray.push(new Promise((resolve, reject) => {
-                  //   const data = fs.writeFileSync('Z:/Source/' + realFileName, file.buffer)
-                  //   resolve({
-                  //     data
-                  //   })
-                  // }));
-
-                  const base64Data = Buffer.from(file.buffer).toString('base64');
-                  const param = {
-                    apiKey: gateWayKey,
-                    email: req.session.account.idTokenClaims.email,
-                    dispFileName: originName,
-                    aipGuid: "878173ae-cc36-4881-af57-604af868314c",
-                    // aipGuid: "0166b75f-6a93-47f3-8fd3-e1e7c59141ab",
-                    // comment: "set-protection",
-                    comment: "set-label",
-                    fileData: base64Data,
-                  }
+                let ext = globalPath.extname(originName);
+                if (supportedArr.length > 0 && !supportedArr.includes(ext)) {
+                  throw '파일명 : ' + originName +'<br>업로드 불가 파일이 포함되어 있습니다.<br>가능 확장자 :' + JSON.stringify(supportedArr);
+                }
 
-                  // labelPromiseArray.push(new Promise(async (resolve)=>{resolve(await axios.post(apiUrl + '/api/v1/stream/set-label', param))}));
-                  labelPromiseArray.push(axios.post(apiUrl + '/api/v1/stream/set-label', param));
-                  // labelPromiseArray.push(axios.post(apiUrl + '/api/v1/stream/set-protection', param));
-                  
-                  let formatPath = '';
+                // const base64Data = Buffer.from(file.buffer).toString('base64');
+                const uuid = uuidv4();
+                const realFileName = uuid + ext;
+                fileWriteArray.push(new Promise((resolve, reject) => {
+                  // const data = fs.writeFileSync('Z:/Source/' + realFileName, file.buffer)
+                  const data = fs.writeFileSync('C:/Users/anrps/OneDrive/바탕 화면/saveDirectory/' + realFileName, file.buffer)
+                  resolve({
+                    data
+                  })
+                }));
+                nameArray.push(realFileName);
+                // const param = {
+                //   apiKey: gateWayKey,
+                //   email: req.session.account.idTokenClaims.email,
+                //   dispFileName: originName,
+                //   aipGuid: "878173ae-cc36-4881-af57-604af868314c",
+                //   // aipGuid: "0166b75f-6a93-47f3-8fd3-e1e7c59141ab",
+                //   // comment: "set-protection",
+                //   comment: "set-label",
+                //   fileData: base64Data,
+                // }
+
+                // return axios.post(apiUrl + '/api/v1/stream/set-label', param).then(async (result)=>{
+                //   let formatPath = '';
+                
+                //   if (file_path[idx]) {
+                //     // console.log(file_path[idx]);
+                //     if (!path.includes(":")) { 
+                //       formatPath = ":" + file_path[idx]; 
+                //     }
+                //     else {
+                //       formatPath = file_path[idx];
+                //     }
+                //   }
+      
+                //   let itemId = '';
+                //   const uri = endPoint + "/sites/"+ siteId + path + formatPath;
+                //   // siteInfoArr.push(axios.get(uri, options));
+                //   if (beforeUri === uri) { 
+                //     itemId = beforeItemId;
+                //   }
+                //   else {
+                //     const sitesInfo = await axios.get(uri, options);
+                //     itemId = sitesInfo.data.id;
+                //     beforeUri = uri;
+                //     beforeItemId = itemId; 
+                //   }
+
+                //   const labelData = result.data;
+                //   if (labelData && labelData.success && !labelData.errorCode && labelData.result.fileData){
+                //     const fileData = labelData.result.fileData;
+                //     const data = Buffer.from(fileData, 'base64');
+                //     return axios.put(endPoint + "/sites/"+ siteId +"/drive/items/"+itemId+':/' + labelData.result.dispFileName + ':/content', data, options);
+                //   }
+                //   else {
+                //     let name = '';
+                //     if (labelData.result && labelData.result.dispFileName) {
+                //       name = ' (파일명 : ' + labelData.result.dispFileName + ')';
+                //     }
+                //     throw new LabelBadResponse(labelData.errorMessage + name);
+                //   }
+                // });
+                // labelPromiseArray.push(axios.post(apiUrl + '/api/v1/stream/set-protection', param));
+                
+                
+                // promiseArray.push(endPoint + "/sites/"+ siteId +"/drive/items/"+itemId+':/');
+            }
+            });
+            await Promise.all(fileWriteArray);
+            console.log(nameArray);
+            console.log('File Write 소요시간', timeCheck(now, new Date()));
+            // for (let idx in files) {
+            //   const file = files[idx];
+            //   file.originalname = Buffer.from(file.originalname, 'ascii').toString('utf8');
+            //   let originName = file.originalname;
+            //   if (originName) {
+            //       let ext = globalPath.extname(originName);
+            //       if (supportedArr.length > 0 && !supportedArr.includes(ext)) {
+            //           return res.json({success:'F', message: '파일명 : ' + originName 
+            //                             +'<br>업로드 불가 파일이 포함되어 있습니다.<br>가능 확장자 :' 
+            //                             + JSON.stringify(supportedArr)});
+            //       }
+
+            //       const base64Data = Buffer.from(file.buffer).toString('base64');
+            //       const param = {
+            //         apiKey: gateWayKey,
+            //         email: req.session.account.idTokenClaims.email,
+            //         dispFileName: originName,
+            //         aipGuid: "878173ae-cc36-4881-af57-604af868314c",
+            //         // aipGuid: "0166b75f-6a93-47f3-8fd3-e1e7c59141ab",
+            //         // comment: "set-protection",
+            //         comment: "set-label",
+            //         fileData: base64Data,
+            //       }
+
+            //       let formatPath = '';
                   
-                  if (file_path[idx]) {
-                    // console.log(file_path[idx]);
-                    if (!path.includes(":")) { 
-                      formatPath = ":" + file_path[idx]; 
-                    }
-                    else {
-                      formatPath = file_path[idx];
-                    }
-                  }
+            //       if (file_path[idx]) {
+            //         // console.log(file_path[idx]);
+            //         if (!path.includes(":")) { 
+            //           formatPath = ":" + file_path[idx]; 
+            //         }
+            //         else {
+            //           formatPath = file_path[idx];
+            //         }
+            //       }
       
-                  let itemId = '';
-                  const uri = endPoint + "/sites/"+ siteId + path + formatPath;
-                  // siteInfoArr.push(axios.get(uri, options));
-                  if (beforeUri === uri) { 
-                    itemId = beforeItemId;
-                  }
-                  else {
-                    const sitesInfo = await axios.get(uri, options);
-                    itemId = sitesInfo.data.id;
-                    beforeUri = uri;
-                    beforeItemId = itemId; 
-                  }
+            //       let itemId = '';
+            //       const uri = endPoint + "/sites/"+ siteId + path + formatPath;
+            //       // siteInfoArr.push(axios.get(uri, options));
+            //       if (beforeUri === uri) { 
+            //         itemId = beforeItemId;
+            //       }
+            //       else {
+            //         const sitesInfo = await axios.get(uri, options);
+            //         itemId = sitesInfo.data.id;
+            //         beforeUri = uri;
+            //         beforeItemId = itemId; 
+            //       }
+
+            //       labelPromiseArray.push(axios.post(apiUrl + '/api/v1/stream/set-label', param).then((result)=>{
+            //         const labelData = result.data;
+            //         if (labelData && labelData.success && !labelData.errorCode && labelData.result.fileData){
+            //           const fileData = labelData.result.fileData;
+            //           const data = Buffer.from(fileData, 'base64');
+            //           return axios.put(endPoint + "/sites/"+ siteId +"/drive/items/"+itemId+':/' + labelData.result.dispFileName + ':/content', data, options);
+            //         }
+            //         else {
+            //           let name = '';
+            //           if (obj.result && obj.result.dispFileName) {
+            //             name = ' (파일명 : ' + obj.result.dispFileName + ')';
+            //           }
+            //           throw new LabelBadResponse(obj.data.errorMessage + name);
+            //         }
+            //       }));
+            //       // labelPromiseArray.push(axios.post(apiUrl + '/api/v1/stream/set-protection', param));
                   
-                  // if (protectedMap.size > 0 && protectedMap.get(ext)) {
-                  //   let name = originName.replace(ext, '');
-                  //   ext = protectedMap.get(ext);
-                  //   originName = name + ext;
-                  // }
-                  promiseArray.push(endPoint + "/sites/"+ siteId +"/drive/items/"+itemId+':/');
-              }
-            }
+                  
+            //       // promiseArray.push(endPoint + "/sites/"+ siteId +"/drive/items/"+itemId+':/');
+            //   }
+            // }
 
-              // const siteInfos = await Promise.all(siteInfoArr);
-              // siteInfos.forEach((obj)=>{
-              //   promiseArray.push(endPoint + "/sites/"+ siteId +"/drive/items/"+obj.data.id+':/');
-              // })
-              //file write 시 사용
-              //const writeArr = await Promise.all(fileWriteArray);
 
-              let writeTime = timeCheck(fileWriteTime, new Date());
-              console.log('파일 Write Time : '+ writeTime);
-              
+              // let writeTime = timeCheck(fileWriteTime, new Date());
+              // console.log('User File Upload Time: '+ writeTime);              
 
-              const labelTime = new Date();
-              const labelResult = await Promise.all(labelPromiseArray);
-              // console.log(labelResult[0].data.result.fileData);
-              console.log('label time : ', timeCheck(labelTime, new Date()));
-              for (let idx in labelResult) {
-                const obj = labelResult[idx].data;
-                if (obj && obj.success === true && !obj.errorCode && obj.result.fileData) {
-                  const data = Buffer.from(obj.result.fileData, 'base64');
-                  // promiseArray[idx] = new Promise(async (resolve)=> resolve(await axios.put(promiseArray[idx] + obj.data.result.dispFileName + ':/content', data, options)));
-                  promiseArray[idx] = axios.put(promiseArray[idx] + obj.result.dispFileName + ':/content', data, options);
-                  // promiseArray.push(axios.put(endPoint + "/sites/"+ siteId +"/drive/items/"+ siteInfos[idx].data.id + ':/' + obj.data.result.dispFileName + ':/content', data, options));
-                }
-                else {
-                  let name = '';
-                  if (obj.result && obj.result.dispFileName) {
-                    name = ' (파일명 : ' + obj.result.dispFileName + ')';
-                  }
-                  throw new LabelBadResponse(obj.data.errorMessage + name);
-                }
-              }
-              // labelResult.forEach((obj, idx)=>{
-              //   if (obj.data && !obj.data.result.errorCode && obj.data.result.fileData) {
-              //     const data = Buffer.from(obj.data.result.fileData, 'base64');
-              //     promiseArray[idx] = axios.put(promiseArray[idx] + obj.data.result.dispFileName + ':/content', data, options);
-              //     // promiseArray.push(axios.put(endPoint + "/sites/"+ siteId +"/drive/items/"+ siteInfos[idx].data.id + ':/' + obj.data.result.dispFileName + ':/content', data, options));
+              // const labelTime = new Date();
+              // const labelResult = await Promise.all(labelPromiseArray);
+              // console.log('label time : ', timeCheck(labelTime, new Date()));
+              // for (let idx in labelResult) {
+              //   const obj = labelResult[idx].data;
+              //   if (obj && obj.success === true && !obj.errorCode && obj.result.fileData) {
+              //     const data = Buffer.from(obj.result.fileData, 'base64');
+              //     promiseArray[idx] = axios.put(promiseArray[idx] + obj.result.dispFileName + ':/content', data, options);
               //   }
               //   else {
-              //     throw '파일명 : '+obj.data.result.dispFileName + '<br>에러 : ' + obj.data.result.errorMessage;
+              //     let name = '';
+              //     if (obj.result && obj.result.dispFileName) {
+              //       name = ' (파일명 : ' + obj.result.dispFileName + ')';
+              //     }
+              //     throw new LabelBadResponse(obj.data.errorMessage + name);
               //   }
-              // })
-              // const readArray = [];
-              // labelResult.forEach((obj)=>{
-              //   readArray.push(new Promise((resolve, reject)=>{
-              //       if (obj.data && !obj.data.result.errorCode) {
-              //         fs.readFile('Z:/Target/' + obj.data.result.outputFileName, (err, data)=>{
-              //           if (err) {
-              //             reject({err}); 
-              //           }
-              //           resolve({data});
-              //           //promiseArray[idx] = axios.put(promiseArray[idx], data, options);
-              //         });
-              //       }
-              //       else {
-              //         reject(obj.data.result.errorMessage);
-              //       }
-              //   }))
-              // });
-              // console.log('labelResult : ', labelResult);
-              // let readTime = new Date();
-              // const readResult = await Promise.all(readArray);
-
-              // console.log(readResult);
-              // console.log('File Read time : ', timeCheck(readTime, new Date()));
+              // }
               
+          let writeTime = timeCheck(fileWriteTime, new Date());
+          console.log('User File Upload Time: '+ writeTime);              
 
-              let uploadTime = new Date();
-              // promiseArray.forEach((obj, idx)=>{
-              //   // console.log(readResult[idx].data);
-              //   // console.log(obj[idx]);
-              //   promiseArray[idx] = axios.put(obj, readResult[idx].data, options); 
-              // });
+          let uploadTime = new Date();
 
-              const uploadResult = await Promise.all(promiseArray);
+          // const uploadResult = await Promise.all(labelPromiseArray);
+          // const uploadResult = await Promise.all(promiseArrNew);
               
-              console.log('File uploadTime : ', timeCheck(uploadTime, new Date()));
-          }
-          const endTime = new Date();
-          let betweenTime = timeCheck(startTime, endTime);
-          console.log('시작 시간 :', startTime.toLocaleString(), ', 종료 시간 :', endTime.toLocaleString(), ', 소요 시간 :', betweenTime);
-          res.json({success:'S', message: '요청하신 파일 업로드가 정상적으로 처리 되었습니다.'});
+          console.log('File uploadTime : ', timeCheck(uploadTime, new Date()));
+        }
+        const endTime = new Date();
+        let betweenTime = timeCheck(startTime, endTime);
+        console.log('*** 파일 Upload ...End: 시작 시간 :', startTime.toLocaleString(), ', 종료 시간 :', endTime.toLocaleString(), ', 소요 시간 :', betweenTime);
+        res.json({success:'S', message: '요청하신 파일 업로드가 정상적으로 처리 되었습니다.'});
       }
       else {
         throw new NotFound(`업로드 요청 파라미터 정보를 확인해 주세요.<br>siteId : ${siteId}, path : ${path}`);
@@ -708,10 +747,6 @@ serverApp.post('/api/download',
             if (data && data.success === true && !data.errorCode && data.result.fileData) {
               const fileData = data.result.fileData;
               return res.json({success: 'S', data: fileData, name: data.result.dispFileName})
-              // return res.json({success: 'S', data: fileData, name: data.result.dispFileName})
-              // res.setHeader('Content-disposition', 'attachment; filename=' + data.result.dispFileName);
-              // res.setHeader('Content-type', mime.lookup(data.result.dispFileName));
-              // res.pipe(fileData);
             }
             else {
               let name = '';
@@ -751,12 +786,9 @@ serverApp.post('/api/download',
           }
       }
       else {
-        return res.json({message:'다운로드 파일 정보를 확인 할 수 없습니다.', success:'F'})
+        throw new NotFound('다운로드 파일 정보를 확인 할 수 없습니다.');
+        // return res.json({message:'다운로드 파일 정보를 확인 할 수 없습니다.', success:'F'})
       }
-    // }
-    // catch(error) {
-    //   return res.json({success: 'F', message:'파일 다운로드 중 오류가 발생하였습니다.<br>'+ getErrorMessage(error)});
-    // }
   }
 ));
 

+ 0 - 274
src/auth/AuthProvider.js

@@ -1,274 +0,0 @@
-const msal = require('@azure/msal-node');
-const axios = require('axios');
-
-const { msalConfig } = require('../authConfig');
-
-class AuthProvider {
-    msalConfig;
-    cryptoProvider;
-
-    constructor(msalConfig) {
-        this.msalConfig = msalConfig
-        this.cryptoProvider = new msal.CryptoProvider();
-    };
-
-    login(options = {}) {
-        return async (req, res, next) => {
-            /**
-             * MSAL Node library allows you to pass your custom state as state parameter in the Request object.
-             * The state parameter can also be used to encode information of the app's state before redirect.
-             * You can pass the user's state in the app, such as the page or view they were on, as input to this parameter.
-             */
-            const state = this.cryptoProvider.base64Encode(
-                JSON.stringify({
-                    successRedirect: options.successRedirect || '/',
-                })
-            );
-            
-            const authCodeUrlRequestParams = {
-                state: state,
-
-                /**
-                 * By default, MSAL Node will add OIDC scopes to the auth code url request. For more information, visit:
-                 * https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
-                 */
-                scopes: options.scopes || [],
-                redirectUri: options.redirectUri,
-            };
-
-            const authCodeRequestParams = {
-                state: state,
-
-                /**
-                 * By default, MSAL Node will add OIDC scopes to the auth code request. For more information, visit:
-                 * https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
-                 */
-                scopes: options.scopes || [],
-                redirectUri: options.redirectUri,
-            };
-
-            /**
-             * If the current msal configuration does not have cloudDiscoveryMetadata or authorityMetadata, we will 
-             * make a request to the relevant endpoints to retrieve the metadata. This allows MSAL to avoid making 
-             * metadata discovery calls, thereby improving performance of token acquisition process. For more, see:
-             * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/performance.md
-             */
-            if (!this.msalConfig.auth.cloudDiscoveryMetadata || !this.msalConfig.auth.authorityMetadata) {
-
-                const [cloudDiscoveryMetadata, authorityMetadata] = await Promise.all([
-                    this.getCloudDiscoveryMetadata(this.msalConfig.auth.authority),
-                    this.getAuthorityMetadata(this.msalConfig.auth.authority)
-                ]);
-
-                this.msalConfig.auth.cloudDiscoveryMetadata = JSON.stringify(cloudDiscoveryMetadata);
-                this.msalConfig.auth.authorityMetadata = JSON.stringify(authorityMetadata);
-            }
-
-            const msalInstance = this.getMsalInstance(this.msalConfig);
-            console.log(msalInstance);
-            // trigger the first leg of auth code flow
-            return this.redirectToAuthCodeUrl(
-                authCodeUrlRequestParams,
-                authCodeRequestParams,
-                msalInstance
-            )(req, res, next);
-        };
-    }
-
-    acquireToken(options = {}) {
-        return async (req, res, next) => {
-            try {
-                const msalInstance = this.getMsalInstance(this.msalConfig);
-                /**
-                 * If a token cache exists in the session, deserialize it and set it as the 
-                 * cache for the new MSAL CCA instance. For more, see: 
-                 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/caching.md
-                 */
-                if (req.session.tokenCache) {
-                    msalInstance.getTokenCache().deserialize(req.session.tokenCache);
-                }
-                
-                const tokenResponse = await msalInstance.acquireTokenSilent({
-                    account: req.session.account,
-                    scopes: options.scopes || req.body.scopes || [],
-                });
-                /**
-                 * On successful token acquisition, write the updated token 
-                 * cache back to the session. For more, see: 
-                 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/caching.md
-                 */
-                req.session.tokenCache = msalInstance.getTokenCache().serialize();
-                req.session.accessToken = tokenResponse.accessToken;
-                req.session.idToken = tokenResponse.idToken;
-                req.session.account = tokenResponse.account;
-                req.session.apiUri = req.body.api_uri;
-                req.session.param  = req.body.param;
-                res.redirect(options.successRedirect);
-            } catch (error) {
-                if (error instanceof msal.InteractionRequiredAuthError) {
-                    return this.login({
-                        scopes: options.scopes || [],
-                        redirectUri: options.redirectUri,
-                        successRedirect: options.successRedirect || '/',
-                    })(req, res, next);
-                }
-
-                next(error);
-            }
-        };
-    }
-
-    handleRedirect(options = {}) {
-        return async (req, res, next) => {
-
-            if (!req.body || !req.body.state) {
-                return next(new Error('Error: response not found'));
-            }
-            if (!req.session || !req.session.pkceCodes) {
-                return next(new Error('Error: session pkceCodes not found'));
-            }
-            const authCodeRequest = { 
-                ...req.session.authCodeRequest, 
-                code: req.body.code,
-                codeVerifier: req.session.pkceCodes.verifier,
-            };
-
-            try {
-                const msalInstance = this.getMsalInstance(this.msalConfig);
-
-                if (req.session.tokenCache) {
-                    msalInstance.getTokenCache().deserialize(req.session.tokenCache);
-                }
-
-                const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body);
-
-                req.session.tokenCache = msalInstance.getTokenCache().serialize();
-                req.session.idToken = tokenResponse.idToken;
-                req.session.account = tokenResponse.account;
-                req.session.isAuthenticated = true;
-                const state = JSON.parse(this.cryptoProvider.base64Decode(req.body.state));
-                res.redirect(state.successRedirect);
-            } catch (error) {
-                next(error);
-            }
-        }
-    }
-
-    logout(options = {}) {
-        return (req, res, next) => {
-
-            /**
-             * Construct a logout URI and redirect the user to end the
-             * session with Azure AD. For more information, visit:
-             * https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc#send-a-sign-out-request
-             */
-            let logoutUri = `${this.msalConfig.auth.authority}/oauth2/v2.0/`;
-
-            if (options.postLogoutRedirectUri) {
-                logoutUri += `logout?post_logout_redirect_uri=${options.postLogoutRedirectUri}`;
-            }
-
-            req.session.destroy(() => {
-                res.redirect(logoutUri);
-            });
-        }
-    }
-
-    /**
-     * Instantiates a new MSAL ConfidentialClientApplication object
-     * @param msalConfig: MSAL Node Configuration object 
-     * @returns 
-     */
-    getMsalInstance(msalConfig) {
-        return new msal.ConfidentialClientApplication(msalConfig);
-    }
-
-
-    /**
-     * Prepares the auth code request parameters and initiates the first leg of auth code flow
-     * @param req: Express request object
-     * @param res: Express response object
-     * @param next: Express next function
-     * @param authCodeUrlRequestParams: parameters for requesting an auth code url
-     * @param authCodeRequestParams: parameters for requesting tokens using auth code
-     */
-    redirectToAuthCodeUrl(authCodeUrlRequestParams, authCodeRequestParams, msalInstance) {
-        return async (req, res, next) => {
-            // Generate PKCE Codes before starting the authorization flow
-            const { verifier, challenge } = await this.cryptoProvider.generatePkceCodes();
-           // Set generated PKCE codes and method as session vars
-            req.session.pkceCodes = {
-                challengeMethod: 'S256',
-                verifier: verifier,
-                challenge: challenge,
-            };
-
-            /**
-             * By manipulating the request objects below before each request, we can obtain
-             * auth artifacts with desired claims. For more information, visit:
-             * https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_node.html#authorizationurlrequest
-             * https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_node.html#authorizationcoderequest
-             **/
-            req.session.authCodeUrlRequest = {
-                ...authCodeUrlRequestParams,
-                responseMode: msal.ResponseMode.FORM_POST, // recommended for confidential clients
-                codeChallenge: req.session.pkceCodes.challenge,
-                codeChallengeMethod: req.session.pkceCodes.challengeMethod,
-            };
-
-            req.session.authCodeRequest = {
-                ...authCodeRequestParams,
-                code: '',
-            };
-            
-            try {
-                console.log(req.session);
-                const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest);
-
-                res.redirect(authCodeUrlResponse);
-            } catch (error) {
-                next(error);
-            }
-        };
-    }
-
-    /**
-     * Retrieves cloud discovery metadata from the /discovery/instance endpoint
-     * @returns 
-     */
-    async getCloudDiscoveryMetadata(authority) {
-        const endpoint = 'https://login.microsoftonline.com/common/discovery/instance';
-
-        try {
-            const response = await axios.get(endpoint, {
-                params: {
-                    'api-version': '1.1',
-                    'authorization_endpoint': `${authority}/oauth2/v2.0/authorize`
-                }
-            });
-
-            return await response.data;
-        } catch (error) {
-            throw error;
-        }
-    }
-
-    /**
-     * Retrieves oidc metadata from the openid endpoint
-     * @returns
-     */
-    async getAuthorityMetadata(authority) {
-        const endpoint = `${authority}/v2.0/.well-known/openid-configuration`;
-
-        try {
-            const response = await axios.get(endpoint);
-            return await response.data;
-        } catch (error) {
-            console.log(error);
-        }
-    }
-}
-
-const authProvider = new AuthProvider(msalConfig);
-
-module.exports = authProvider;

+ 0 - 40
src/authConfig.js

@@ -1,40 +0,0 @@
-/*
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License.
- */
-
-require('dotenv').config({ path: './env/.env.test' });
-
-/**
- * Configuration object to be passed to MSAL instance on creation.
- * For a full list of MSAL Node configuration parameters, visit:
- * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
- */
-
-const msalConfig = {
-    auth: {
-        clientId: process.env.CLIENT_ID, // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
-        authority: process.env.CLOUD_INSTANCE + process.env.TENANT_ID, // Full directory URL, in the form of https://login.microsoftonline.com/<tenant>
-        clientSecret: process.env.CLIENT_SECRET // Client secret generated from the app registration in Azure portal
-    },
-    system: {
-        loggerOptions: {
-            loggerCallback(loglevel, message, containsPii) {
-                console.log(message);
-            },
-            piiLoggingEnabled: false,
-            logLevel: 3,
-        }
-    }
-}
-
-const REDIRECT_URI = process.env.REDIRECT_URI;
-const POST_LOGOUT_REDIRECT_URI = process.env.POST_LOGOUT_REDIRECT_URI;
-const GRAPH_ME_ENDPOINT = process.env.GRAPH_API_ENDPOINT + "v1.0/me";
-
-module.exports = {
-    msalConfig,
-    REDIRECT_URI,
-    POST_LOGOUT_REDIRECT_URI,
-    GRAPH_ME_ENDPOINT
-};

+ 0 - 31
src/routes/auth.js

@@ -1,31 +0,0 @@
-/*
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License.
- */
-
-var express = require('express');
-
-const authProvider = require('../auth/AuthProvider');
-const { REDIRECT_URI, POST_LOGOUT_REDIRECT_URI } = require('../authConfig');
-
-const router = express.Router();
-
-router.get('/signin', authProvider.login({
-    scopes: [],
-    redirectUri: REDIRECT_URI,
-    successRedirect: '/'
-}));
-
-router.get('/acquireToken', authProvider.acquireToken({
-    scopes: ['User.Read'],
-    redirectUri: REDIRECT_URI,
-    successRedirect: '/users/profile'
-}));
-
-router.post('/redirect', authProvider.handleRedirect());
-
-router.get('/signout', authProvider.logout({
-    postLogoutRedirectUri: POST_LOGOUT_REDIRECT_URI
-}));
-
-module.exports = router;

+ 0 - 17
src/routes/index.js

@@ -1,17 +0,0 @@
-/*
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License.
- */
-
-var express = require('express');
-var router = express.Router();
-
-router.get('/', function (req, res, next) {
-    res.render('index', {
-        title: 'MSAL Node & Express Web App',
-        isAuthenticated: req.session.isAuthenticated,
-        username: req.session.account?.username,
-    });
-});
-
-module.exports = router;

+ 0 - 41
src/routes/users.js

@@ -1,41 +0,0 @@
-/*
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License.
- */
-
-var express = require('express');
-var router = express.Router();
-
-var fetch = require('../fetch');
-
-var { GRAPH_ME_ENDPOINT } = require('../authConfig');
-
-// custom middleware to check auth state
-function isAuthenticated(req, res, next) {
-    if (!req.session.isAuthenticated) {
-        return res.redirect('/tab-auth'); // redirect to sign-in route
-    }
-
-    next();
-};
-
-router.get('/id',
-    isAuthenticated, // check if user is authenticated
-    async function (req, res, next) {
-        res.render('id', { idTokenClaims: req.session.account.idTokenClaims });
-    }
-);
-
-router.get('/profile',
-    isAuthenticated, // check if user is authenticated
-    async function (req, res, next) {
-        try {
-            const graphResponse = await fetch(GRAPH_ME_ENDPOINT, req.session.accessToken);
-            res.render('profile', { profile: graphResponse });
-        } catch (error) {
-            next(error);
-        }
-    }
-);
-
-module.exports = router;

+ 1 - 0
src/views/hello.html

@@ -1221,6 +1221,7 @@
               fileIdArr.push({id : fileArr.eq(ii).val()});
             }
         }
+        console.log(fileArr);
         if (fileIdArr.length === 0) return alertMessage('다운로드', '다운로드 할 파일을 선택해주세요.');
 
         $.ajax({

BIN
test - 복사본 (3).xlsx