Showing
48 changed files
with
1864 additions
and
112 deletions
... | @@ -8,6 +8,7 @@ const fileStore = require('session-file-store')(session); | ... | @@ -8,6 +8,7 @@ const fileStore = require('session-file-store')(session); |
8 | const app = express(); | 8 | const app = express(); |
9 | var flash = require('connect-flash'); | 9 | var flash = require('connect-flash'); |
10 | var NaverStrategy = require('passport-naver').Strategy; | 10 | var NaverStrategy = require('passport-naver').Strategy; |
11 | +var KakaoStrategy = require('passport-kakao').Strategy; | ||
11 | 12 | ||
12 | 13 | ||
13 | 14 | ||
... | @@ -51,11 +52,12 @@ app.get('/main',(req,res)=>{ | ... | @@ -51,11 +52,12 @@ app.get('/main',(req,res)=>{ |
51 | }) | 52 | }) |
52 | 53 | ||
53 | 54 | ||
55 | +/*--------------------로그인 처리---------------------- */ | ||
56 | + | ||
54 | //로그인 페이지 | 57 | //로그인 페이지 |
55 | app.get('/login',(req,res)=>{ | 58 | app.get('/login',(req,res)=>{ |
56 | let page = getLoginButton(`<a href="/">뒤로가기</a>`); | 59 | let page = getLoginButton(`<a href="/">뒤로가기</a>`); |
57 | res.send(page); | 60 | res.send(page); |
58 | - | ||
59 | }); | 61 | }); |
60 | 62 | ||
61 | 63 | ||
... | @@ -96,25 +98,65 @@ passport.authenticate('local', { | ... | @@ -96,25 +98,65 @@ passport.authenticate('local', { |
96 | failureFlash: true | 98 | failureFlash: true |
97 | })); | 99 | })); |
98 | 100 | ||
101 | +//로그 아웃 처리 | ||
102 | +app.get('/logout',(req,res)=>{ | ||
103 | + | ||
104 | + //passport 정보 삭제 | ||
105 | + req.logout(); | ||
106 | + //서버측 세션 삭제 | ||
107 | + req.session.destroy(()=>{ | ||
108 | + //클라이언트 측 세션 암호화 쿠키 삭제 | ||
109 | + res.cookie('connect.sid','',{maxAge:0}); | ||
110 | + res.redirect('/'); | ||
111 | + }); | ||
112 | +}); | ||
113 | + | ||
114 | + | ||
115 | +//로그인 로그아웃 여부 | ||
116 | +const authInfo = (req)=>{ | ||
117 | + if(req.user) return `${user.name} | <a href="/logout">로그아웃</a>`; | ||
118 | + return `<a href="/login">로그인</a>`; | ||
119 | +} | ||
120 | + | ||
121 | +// naver 로그인 | ||
122 | +app.get('/naverlogin', passport.authenticate('naver')); | ||
123 | +passport.use('naver',new NaverStrategy({ | ||
124 | + clientID: 'CGVVomc0bhMhzfzbytK2', | ||
125 | + clientSecret: 'XHylcjnZxG', | ||
126 | + callbackURL: "http://localhost:3000/", | ||
127 | + svcType: 0, | ||
128 | + authType: 'reauthenticate' // enable re-authentication | ||
129 | + }, | ||
130 | + | ||
131 | + function(accessToken, refreshToken, profile, done) { | ||
132 | + var _profile = profile._json; | ||
133 | + console.log(_profile.id); | ||
134 | + console.log(_profile.properties.nickname); | ||
135 | + } | ||
136 | + )); | ||
137 | + | ||
138 | + | ||
139 | +// kakao 로그인 | ||
140 | +app.get('/kakaologin', passport.authenticate('kakao-login')); | ||
141 | +passport.use('kakao-login', new KakaoStrategy({ | ||
142 | + clientID: '8a854307a99092b4eeeff5e4a79c0ac0', | ||
143 | + callbackURL: 'http://localhost:3000/' | ||
144 | +}, | ||
145 | +function (accessToken, refreshToken, profile, done) { | ||
146 | + var _profile = profile._json; | ||
147 | + console.log(_profile.id); | ||
148 | + console.log(_profile.properties.nickname); | ||
149 | + | ||
150 | +} | ||
151 | +)); | ||
152 | + | ||
153 | + | ||
154 | +/*--------------------회원가입 처리---------------------- */ | ||
155 | + | ||
99 | 156 | ||
100 | //회원가입 페이지 Get | 157 | //회원가입 페이지 Get |
101 | app.get('/join',(req,res)=>{ | 158 | app.get('/join',(req,res)=>{ |
102 | -<<<<<<< HEAD | 159 | + let page = getPage('회원가입',` |
103 | - let page = getPage('회원가입',` | ||
104 | - <script> function congratulation() | ||
105 | - { | ||
106 | - alert("새로운 회원이 되신걸 축하합니다!:D 레시피 찾을 준비 되셨나요?"); | ||
107 | - } </script> | ||
108 | - <form action="/join" method="post"> | ||
109 | - <input type="email" name="email" placeholder="email"><br> | ||
110 | - <input type="password" name="password" placeholder="****"><br> | ||
111 | - <input type="name" name="name" placeholder="이름"><br> | ||
112 | - <input type="submit" value="회원가입" onClick="javascript:congratulation()"><br> | ||
113 | - </form> | ||
114 | - `,'<a href="/login">뒤로가기</a>'); | ||
115 | - res.send(page); | ||
116 | -======= | ||
117 | - let page = getPage('',` | ||
118 | <html> | 160 | <html> |
119 | <head> | 161 | <head> |
120 | <style> | 162 | <style> |
... | @@ -195,42 +237,14 @@ app.get('/join',(req,res)=>{ | ... | @@ -195,42 +237,14 @@ app.get('/join',(req,res)=>{ |
195 | </html> | 237 | </html> |
196 | `,'<a href="/login">뒤로가기</a>'); | 238 | `,'<a href="/login">뒤로가기</a>'); |
197 | res.send(page); | 239 | res.send(page); |
198 | ->>>>>>> 04a7922847fd162bc1b11e832ee65246c056146d | ||
199 | -}); | ||
200 | - | ||
201 | -//회원가입 처리 Post : 예제를 위해 간단 저장 방식으로 구현 | ||
202 | -var user = {}; | ||
203 | -app.post('/join',(req,res)=>{ | ||
204 | - user.email = req.body.email; | ||
205 | - user.password = req.body.password; | ||
206 | - user.name=req.body.name; | ||
207 | - //로그인 페이지로 이동 | ||
208 | - res.redirect('/login'); | ||
209 | }); | 240 | }); |
210 | 241 | ||
211 | -//로그 아웃 처리 | ||
212 | -app.get('/logout',(req,res)=>{ | ||
213 | - | ||
214 | - //passport 정보 삭제 | ||
215 | - req.logout(); | ||
216 | - //서버측 세션 삭제 | ||
217 | - req.session.destroy(()=>{ | ||
218 | - //클라이언트 측 세션 암호화 쿠키 삭제 | ||
219 | - res.cookie('connect.sid','',{maxAge:0}); | ||
220 | - res.redirect('/'); | ||
221 | - }); | ||
222 | -}); | ||
223 | 242 | ||
224 | 243 | ||
225 | //포트 연결 | 244 | //포트 연결 |
226 | app.listen(3000,()=>console.log(`http://localhost:3000`)); | 245 | app.listen(3000,()=>console.log(`http://localhost:3000`)); |
227 | 246 | ||
228 | 247 | ||
229 | -//로그인 로그아웃 여부 | ||
230 | -const authInfo = (req)=>{ | ||
231 | - if(req.user) return `${user.name} | <a href="/logout">로그아웃</a>`; | ||
232 | - return `<a href="/login">로그인</a>`; | ||
233 | -} | ||
234 | 248 | ||
235 | //페이지 템플릿 | 249 | //페이지 템플릿 |
236 | const getPage = (title, content, auth) =>{ | 250 | const getPage = (title, content, auth) =>{ |
... | @@ -341,22 +355,19 @@ const getLoginButton = (auth) =>{ | ... | @@ -341,22 +355,19 @@ const getLoginButton = (auth) =>{ |
341 | </div> | 355 | </div> |
342 | </div> | 356 | </div> |
343 | </div> | 357 | </div> |
344 | - <!-- 네이버 로그인 버튼 노출 영역 --> | 358 | + |
345 | - <div id="naver_id_login"></div> | 359 | + <div> |
346 | - <!-- //네이버 로그인 버튼 노출 영역 --> | 360 | + <a href="/naverlogin" class="btn btn-block btn-lg btn-success btn_login">Naver</a> |
347 | - <script type="text/javascript"> | 361 | + <a href="/kakaologin" class="btn btn-block btn-lg btn-warning btn_login">KaKao</a> |
348 | - var naver_id_login = new naver_id_login("CGVVomc0bhMhzfzbytK2", "http://localhost:3000/naverlogin"); | 362 | + </div> |
349 | - var state = naver_id_login.getUniqState(); | 363 | + |
350 | - naver_id_login.setButton("white", 2,40); | 364 | + |
351 | - naver_id_login.setState(state); | ||
352 | - naver_id_login.setPopup(); | ||
353 | - naver_id_login.init_naver_id_login(); | ||
354 | - </script> | ||
355 | </body> | 365 | </body> |
356 | </html> | 366 | </html> |
357 | `; | 367 | `; |
358 | } | 368 | } |
359 | 369 | ||
370 | + | ||
360 | //첫 페이지 화면 | 371 | //첫 페이지 화면 |
361 | const getFirstPage =(title, content, auth) =>{ | 372 | const getFirstPage =(title, content, auth) =>{ |
362 | return ` | 373 | return ` |
... | @@ -385,36 +396,3 @@ const getFirstPage =(title, content, auth) =>{ | ... | @@ -385,36 +396,3 @@ const getFirstPage =(title, content, auth) =>{ |
385 | 396 | ||
386 | } | 397 | } |
387 | 398 | ||
388 | - | ||
389 | -var client_id = 'CGVVomc0bhMhzfzbytK2'; | ||
390 | -var client_secret = 'XHylcjnZxG'; | ||
391 | -var state = "RAMDOM_STATE"; | ||
392 | -var redirectURI = encodeURI("http://localhost:3000/"); | ||
393 | -var api_url = ""; | ||
394 | - | ||
395 | - | ||
396 | -app.get('/naverlogin', function (req, res) { | ||
397 | - api_url = 'https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=' + client_id + '&redirect_uri=' + redirectURI + '&state=' + state; | ||
398 | - res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'}); | ||
399 | - res.end("<a href='"+ api_url + "'><img height='50' src='http://static.nid.naver.com/oauth/small_g_in.PNG'/></a>"); | ||
400 | - }); | ||
401 | - app.get('/callback', function (req, res) { | ||
402 | - code = req.query.code; | ||
403 | - state = req.query.state; | ||
404 | - api_url = 'https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&client_id=' | ||
405 | - + client_id + '&client_secret=' + client_secret + '&redirect_uri=' + redirectURI + '&code=' + code + '&state=' + state; | ||
406 | - var request = require('request'); | ||
407 | - var options = { | ||
408 | - url: api_url, | ||
409 | - headers: {'X-Naver-Client-Id':client_id, 'X-Naver-Client-Secret': client_secret} | ||
410 | - }; | ||
411 | - request.get(options, function (error, response, body) { | ||
412 | - if (!error && response.statusCode == 200) { | ||
413 | - res.writeHead(200, {'Content-Type': 'text/json;charset=utf-8'}); | ||
414 | - res.end(body); | ||
415 | - } else { | ||
416 | - res.status(response.statusCode).end(); | ||
417 | - console.log('error = ' + response.statusCode); | ||
418 | - } | ||
419 | - }); | ||
420 | - }); | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
naver_login/naverlogin.html
deleted
100644 → 0
1 | -<!doctype html> | ||
2 | -<html lang="ko"> | ||
3 | -<head> | ||
4 | - <meta charset="utf-8"> | ||
5 | - <title>네이버 로그인</title> | ||
6 | - <script type="text/javascript" src="https://static.nid.naver.com/js/naverLogin_implicit-1.0.3.js" charset="utf-8"></script> | ||
7 | - <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script> | ||
8 | -</head> | ||
9 | -<body> | ||
10 | - <!-- 네이버 로그인 버튼 노출 영역 --> | ||
11 | - <div id="naver_id_login"></div> | ||
12 | - <!-- //네이버 로그인 버튼 노출 영역 --> | ||
13 | - <script type="text/javascript"> | ||
14 | - var naver_id_login = new naver_id_login("CGVVomc0bhMhzfzbytK2", "http://localhost:3000/"); | ||
15 | - var state = naver_id_login.getUniqState(); | ||
16 | - naver_id_login.setButton("white", 2,40); | ||
17 | - naver_id_login.setDomain("http://localhost:3000/"); | ||
18 | - naver_id_login.setState(state); | ||
19 | - naver_id_login.setPopup(); | ||
20 | - naver_id_login.init_naver_id_login(); | ||
21 | - </script> | ||
22 | -</html> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -1713,6 +1713,28 @@ | ... | @@ -1713,6 +1713,28 @@ |
1713 | "node": ">= 0.4.0" | 1713 | "node": ">= 0.4.0" |
1714 | } | 1714 | } |
1715 | }, | 1715 | }, |
1716 | + "node_modules/passport-kakao": { | ||
1717 | + "version": "1.0.1", | ||
1718 | + "resolved": "https://registry.npmjs.org/passport-kakao/-/passport-kakao-1.0.1.tgz", | ||
1719 | + "integrity": "sha512-uItaYRVrTHL6iGPMnMZvPa/O1GrAdh/V6EMjOHcFlQcVroZ9wgG7BZ5PonMNJCxfHQ3L2QVNRnzhKWUzSsumbw==", | ||
1720 | + "dependencies": { | ||
1721 | + "passport-oauth2": "~1.1.2", | ||
1722 | + "pkginfo": "~0.3.0" | ||
1723 | + } | ||
1724 | + }, | ||
1725 | + "node_modules/passport-kakao/node_modules/passport-oauth2": { | ||
1726 | + "version": "1.1.2", | ||
1727 | + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.1.2.tgz", | ||
1728 | + "integrity": "sha1-vXFjsbYJA3GGjcTvb58uHkzEuUg=", | ||
1729 | + "dependencies": { | ||
1730 | + "oauth": "0.9.x", | ||
1731 | + "passport-strategy": "1.x.x", | ||
1732 | + "uid2": "0.0.x" | ||
1733 | + }, | ||
1734 | + "engines": { | ||
1735 | + "node": ">= 0.4.0" | ||
1736 | + } | ||
1737 | + }, | ||
1716 | "node_modules/passport-local": { | 1738 | "node_modules/passport-local": { |
1717 | "version": "1.0.0", | 1739 | "version": "1.0.0", |
1718 | "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", | 1740 | "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", |
... | @@ -1827,6 +1849,14 @@ | ... | @@ -1827,6 +1849,14 @@ |
1827 | "url": "https://github.com/sponsors/jonschlinkert" | 1849 | "url": "https://github.com/sponsors/jonschlinkert" |
1828 | } | 1850 | } |
1829 | }, | 1851 | }, |
1852 | + "node_modules/pkginfo": { | ||
1853 | + "version": "0.3.1", | ||
1854 | + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", | ||
1855 | + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=", | ||
1856 | + "engines": { | ||
1857 | + "node": ">= 0.4.0" | ||
1858 | + } | ||
1859 | + }, | ||
1830 | "node_modules/prepend-http": { | 1860 | "node_modules/prepend-http": { |
1831 | "version": "2.0.0", | 1861 | "version": "2.0.0", |
1832 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", | 1862 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", | ... | ... |
node_modules/passport-kakao/.eslintrc.js
0 → 100644
1 | +module.exports = { | ||
2 | + env: { | ||
3 | + es6: true, | ||
4 | + }, | ||
5 | + extends: [ | ||
6 | + 'eslint:recommended', | ||
7 | + 'plugin:@typescript-eslint/eslint-recommended', | ||
8 | + 'plugin:@typescript-eslint/recommended', | ||
9 | + ], | ||
10 | + globals: { | ||
11 | + Atomics: 'readonly', | ||
12 | + SharedArrayBuffer: 'readonly', | ||
13 | + }, | ||
14 | + parser: '@typescript-eslint/parser', | ||
15 | + parserOptions: { | ||
16 | + ecmaFeatures: { | ||
17 | + jsx: true, | ||
18 | + }, | ||
19 | + ecmaVersion: 2018, | ||
20 | + sourceType: 'module', | ||
21 | + }, | ||
22 | + plugins: ['@typescript-eslint'], | ||
23 | + settings: { | ||
24 | + react: { | ||
25 | + version: 'detect', | ||
26 | + }, | ||
27 | + }, | ||
28 | + rules: { | ||
29 | + semi: ['warn', 'never'], | ||
30 | + 'sort-imports': ['off'], | ||
31 | + quotes: ['warn', 'single'], | ||
32 | + 'no-extra-boolean-cast': ['off'], | ||
33 | + '@typescript-eslint/member-delimiter-style': [ | ||
34 | + 'warn', | ||
35 | + { | ||
36 | + multiline: { | ||
37 | + delimiter: 'none', | ||
38 | + requireLast: false, | ||
39 | + }, | ||
40 | + singleline: { | ||
41 | + requireLast: false, | ||
42 | + }, | ||
43 | + }, | ||
44 | + ], | ||
45 | + '@typescript-eslint/no-empty-interface': ['off'], | ||
46 | + '@typescript-eslint/explicit-function-return-type': ['off'], | ||
47 | + '@typescript-eslint/no-explicit-any': ['off'], | ||
48 | + '@typescript-eslint/no-non-null-assertion': ['off'], | ||
49 | + '@typescript-eslint/interface-name-prefix': ['warn'], | ||
50 | + }, | ||
51 | +} |
node_modules/passport-kakao/.prettierrc
0 → 100644
node_modules/passport-kakao/.travis.yml
0 → 100644
node_modules/passport-kakao/README.md
0 → 100644
1 | +# passport-kakao | ||
2 | + | ||
3 | +kakao oauth2 로그인과 passport 모듈 연결체. | ||
4 | + | ||
5 | +## install | ||
6 | + | ||
7 | +```sh | ||
8 | +npm install passport-kakao | ||
9 | +``` | ||
10 | + | ||
11 | +## how to use | ||
12 | + | ||
13 | +- https://developers.kakao.com/ 에서 애플리케이션을 등록한다. | ||
14 | +- 방금 추가한 애플리케이션의 설정 - 사용자 관리에 들어가서 사용을 ON으로 한 뒤 저장한다. | ||
15 | +- 설정 - 일반에서, 플랫폼 추가를 누른 후 웹 플랫폼을 추가한다. | ||
16 | +- 웹 플랫폼 설정의 사이트 도메인에 자신의 사이트 도메인을 추가한다. (ex : http://localhost:3000) | ||
17 | +- 프로그램 상에서는 아래와 같이 사용한다. | ||
18 | + | ||
19 | +> clientSecret을 활성화 한 경우 해당 파라메터를 같이 넘겨줘야한다. | ||
20 | + | ||
21 | +```javascript | ||
22 | +const passport = require('passport') | ||
23 | +const KakaoStrategy = require('passport-kakao').Strategy | ||
24 | + | ||
25 | +passport.use(new KakaoStrategy({ | ||
26 | + clientID : clientID, | ||
27 | + clientSecret: clientSecret, // clientSecret을 사용하지 않는다면 넘기지 말거나 빈 스트링을 넘길 것 | ||
28 | + callbackURL : callbackURL | ||
29 | + }, | ||
30 | + (accessToken, refreshToken, profile, done) => { | ||
31 | + // 사용자의 정보는 profile에 들어있다. | ||
32 | + User.findOrCreate(..., (err, user) => { | ||
33 | + if (err) { return done(err) } | ||
34 | + return done(null, user) | ||
35 | + }) | ||
36 | + } | ||
37 | +)) | ||
38 | +``` | ||
39 | + | ||
40 | +> 기본 callbackPath는 `/oauth` 이고 https://developers.kakao.com 에서 수정할 수 있다. 하지만 callbackURL은 `사이트 도메인/oauth` 로 설정하는 것을 권장함. (ex : http://myhomepage.com:3000/oauth ) | ||
41 | + | ||
42 | +## | ||
43 | + | ||
44 | +## profile property | ||
45 | + | ||
46 | +profile에는 아래의 property들이 설정되어 넘겨진다. | ||
47 | + | ||
48 | +| key | value | 비고 | | ||
49 | +| -------- | ------ | ------------------------------------------ | | ||
50 | +| provider | String | kakao 고정 | | ||
51 | +| id | Number | 사용자의 kakao id | | ||
52 | +| \_raw | String | 사용자 정보 조회로 얻어진 json string | | ||
53 | +| \_json | Object | 사용자 정보 조회로 얻어진 json 원본 데이터 | | ||
54 | + | ||
55 | +## simple sample | ||
56 | + | ||
57 | +### 설치 & 실행 | ||
58 | + | ||
59 | +1. `./sample/sample.js` 의 `appKey` 를 https://developers.kakao.com 에서 발급받은 JS appKey 값으로 셋팅. | ||
60 | +2. command line 에서 아래의 커맨드 실행 | ||
61 | +3. 브라우져를 열고 `127.0.0.1:3000/login` 을 입력 후 이후 과정을 진행한다. | ||
62 | + | ||
63 | +``` | ||
64 | +cd ./sample | ||
65 | +npm install | ||
66 | +node app | ||
67 | +``` | ||
68 | + | ||
69 | +## mean.io 와 쉽게 연동하기 | ||
70 | + | ||
71 | +수정해야하는 파일들은 아래와 같다. | ||
72 | + | ||
73 | +| file path | 설명 | | ||
74 | +| -------------------------------- | ------------------------------ | | ||
75 | +| server/config/env/development.js | 개발환경 설정파일 | | ||
76 | +| server/config/env/production.js | 운영환경 설정파일 | | ||
77 | +| server/config/models/user.js | 사용자 모델 | | ||
78 | +| server/config/passport.js | passport script | | ||
79 | +| server/routes/users.js | 사용자 로그인 관련 routes file | | ||
80 | +| public/auth/views/index.html | 로그인 화면 | | ||
81 | + | ||
82 | +(1) **mean.io app을 생성** 한다. (ex : mean init kakaoTest) | ||
83 | + | ||
84 | +(2) 해당 모듈을 연동할 mean.io app에 설치한다.(npm install passport-kakao --save) | ||
85 | + | ||
86 | +(3) **server/config/env/development.js** 와 **production.js** 에 kakao 관련 설정을 아래와 같이 추가한다. | ||
87 | + | ||
88 | +```javascript | ||
89 | +'use strict' | ||
90 | + | ||
91 | +module.exports = { | ||
92 | + db: 'mongodb', | ||
93 | + app: { | ||
94 | + name: 'passport-kakao', | ||
95 | + }, | ||
96 | + // 그외 설정들...., | ||
97 | + kakao: { | ||
98 | + clientID: 'kakao app rest api key', | ||
99 | + callbackURL: 'http://localhost:3000/oauth', | ||
100 | + }, | ||
101 | +} | ||
102 | +``` | ||
103 | + | ||
104 | +(4) **server/config/models/users.js** 의 사용자 스키마 정의에 **kakao: {}** 를 추가한다. | ||
105 | + | ||
106 | +(5) **server/config/passport.js** 파일에 아래 구문을 추가한다. | ||
107 | + | ||
108 | +```javascript | ||
109 | +// 최상단 require되는 구문에 추가 | ||
110 | +var KakaoStrategy = require('passport-kakao').Strategy | ||
111 | + | ||
112 | +passport.use( | ||
113 | + new KakaoStrategy( | ||
114 | + { | ||
115 | + clientID: config.kakao.clientID, | ||
116 | + callbackURL: config.kakao.callbackURL, | ||
117 | + }, | ||
118 | + function(accessToken, refreshToken, profile, done) { | ||
119 | + User.findOne( | ||
120 | + { | ||
121 | + 'kakao.id': profile.id, | ||
122 | + }, | ||
123 | + function(err, user) { | ||
124 | + if (err) { | ||
125 | + return done(err) | ||
126 | + } | ||
127 | + if (!user) { | ||
128 | + user = new User({ | ||
129 | + name: profile.username, | ||
130 | + username: profile.id, | ||
131 | + roles: ['authenticated'], | ||
132 | + provider: 'kakao', | ||
133 | + kakao: profile._json, | ||
134 | + }) | ||
135 | + | ||
136 | + user.save(function(err) { | ||
137 | + if (err) { | ||
138 | + console.log(err) | ||
139 | + } | ||
140 | + return done(err, user) | ||
141 | + }) | ||
142 | + } else { | ||
143 | + return done(err, user) | ||
144 | + } | ||
145 | + } | ||
146 | + ) | ||
147 | + } | ||
148 | + ) | ||
149 | +) | ||
150 | +``` | ||
151 | + | ||
152 | +(6) **server/routes/users.js** 에 아래와 같은 구문을 추가한다. | ||
153 | + | ||
154 | +```javascript | ||
155 | +app.get( | ||
156 | + '/auth/kakao', | ||
157 | + passport.authenticate('kakao', { | ||
158 | + failureRedirect: '#!/login', | ||
159 | + }), | ||
160 | + users.signin | ||
161 | +) | ||
162 | + | ||
163 | +app.get( | ||
164 | + '/oauth', | ||
165 | + passport.authenticate('kakao', { | ||
166 | + failureRedirect: '#!/login', | ||
167 | + }), | ||
168 | + users.authCallback | ||
169 | +) | ||
170 | +``` | ||
171 | + | ||
172 | +(7) **public/auth/views/index.html** 에 kakao login을 연결한다. | ||
173 | + | ||
174 | +```html | ||
175 | +<!-- 아래는 예시 --> | ||
176 | +<div> | ||
177 | + <div class="row"> | ||
178 | + <div class="col-md-offset-1 col-md-5"> | ||
179 | + <a href="/auth/facebook"> | ||
180 | + <img src="/public/auth/assets/img/icons/facebook.png" /> | ||
181 | + </a> | ||
182 | + <a href="/auth/twitter"> | ||
183 | + <img src="/public/auth/assets/img/icons/twitter.png" /> | ||
184 | + </a> | ||
185 | + | ||
186 | + <!-- kakao login --> | ||
187 | + <a href="/auth/kakao"> | ||
188 | + <img | ||
189 | + src="https://developers.kakao.com/assets/img/about/logos/kakaolink/kakaolink_btn_medium.png" | ||
190 | + /> | ||
191 | + </a> | ||
192 | + </div> | ||
193 | + </div> | ||
194 | + <div class="col-md-6"> | ||
195 | + <div ui-view></div> | ||
196 | + </div> | ||
197 | +</div> | ||
198 | +``` | ||
199 | + | ||
200 | +(8) grunt로 mean.io app 실행 후, 실제 로그인 연동 테스트를 해본다. | ||
201 | + | ||
202 | +## 기타 | ||
203 | + | ||
204 | +passport-oauth 모듈과 passport-facebook 모듈을 참고함. |
node_modules/passport-kakao/dist/Strategy.js
0 → 100644
1 | +"use strict"; | ||
2 | +var __importDefault = (this && this.__importDefault) || function (mod) { | ||
3 | + return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
4 | +}; | ||
5 | +Object.defineProperty(exports, "__esModule", { value: true }); | ||
6 | +var util_1 = require("util"); | ||
7 | +var passport_oauth2_1 = __importDefault(require("passport-oauth2")); | ||
8 | +var DEFAULT_CLIENT_SECRET = 'kakao'; | ||
9 | +var OAUTH_HOST = 'https://kauth.kakao.com'; | ||
10 | +var USER_PROFILE_URL = 'https://kapi.kakao.com/v2/user/me'; | ||
11 | +exports.buildOptions = function (options) { | ||
12 | + options.authorizationURL = OAUTH_HOST + "/oauth/authorize"; | ||
13 | + options.tokenURL = OAUTH_HOST + "/oauth/token"; | ||
14 | + if (!options.clientSecret) { | ||
15 | + options.clientSecret = DEFAULT_CLIENT_SECRET; | ||
16 | + } | ||
17 | + options.scopeSeparator = options.scopeSeparator || ','; | ||
18 | + options.customHeaders = options.customHeaders || {}; | ||
19 | + if (!options.customHeaders['User-Agent']) { | ||
20 | + options.customHeaders['User-Agent'] = options.userAgent || 'passport-kakao'; | ||
21 | + } | ||
22 | + return options; | ||
23 | +}; | ||
24 | +/** | ||
25 | + * KaKaoStrategy 생성자 함수.<br/> | ||
26 | + * @param options.clientID 필수. kakao rest app key. | ||
27 | + * @param options.callbackURL 필수. 로그인 처리 후 호출할 URL | ||
28 | + * @param verify | ||
29 | + * @constructor | ||
30 | + */ | ||
31 | +function Strategy(options, verify) { | ||
32 | + if (options === void 0) { options = {}; } | ||
33 | + passport_oauth2_1.default.call(this, exports.buildOptions(options), verify); | ||
34 | + this.name = 'kakao'; | ||
35 | + this._userProfileURL = USER_PROFILE_URL; | ||
36 | +} | ||
37 | +/** | ||
38 | + * `OAuth2Stragegy`를 상속 받는다. | ||
39 | + */ | ||
40 | +util_1.inherits(Strategy, passport_oauth2_1.default); | ||
41 | +/** | ||
42 | + * kakao 사용자 정보를 얻는다.<br/> | ||
43 | + * 사용자 정보를 성공적으로 조회하면 아래의 object가 done 콜백함수 호출과 함꼐 넘어간다. | ||
44 | + * | ||
45 | + * - `provider` kakao 고정 | ||
46 | + * - `id` kakao user id number | ||
47 | + * - `username` 사용자의 kakao nickname | ||
48 | + * - `_raw` json string 원문 | ||
49 | + * _ `_json` json 원 데이터 | ||
50 | + * | ||
51 | + * @param {String} accessToken | ||
52 | + * @param {Function} done | ||
53 | + */ | ||
54 | +Strategy.prototype.userProfile = function (accessToken, done) { | ||
55 | + this._oauth2.get(this._userProfileURL, accessToken, function (err, body) { | ||
56 | + if (err) { | ||
57 | + return done(err); | ||
58 | + } | ||
59 | + try { | ||
60 | + var json = JSON.parse(body); | ||
61 | + // 카카오톡이나 카카오스토리에 연동한 적이 없는 계정의 경우 | ||
62 | + // properties가 비어있다고 한다. 없을 경우의 처리 | ||
63 | + var properties = json.properties || { | ||
64 | + nickname: '미연동 계정', | ||
65 | + }; | ||
66 | + var profile = { | ||
67 | + provider: 'kakao', | ||
68 | + id: json.id, | ||
69 | + username: properties.nickname, | ||
70 | + displayName: properties.nickname, | ||
71 | + _raw: body, | ||
72 | + _json: json, | ||
73 | + }; | ||
74 | + return done(null, profile); | ||
75 | + } | ||
76 | + catch (e) { | ||
77 | + return done(e); | ||
78 | + } | ||
79 | + }); | ||
80 | +}; | ||
81 | +exports.default = Strategy; |
1 | +"use strict"; | ||
2 | +var __importDefault = (this && this.__importDefault) || function (mod) { | ||
3 | + return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
4 | +}; | ||
5 | +Object.defineProperty(exports, "__esModule", { value: true }); | ||
6 | +var Strategy_1 = __importDefault(require("./Strategy")); | ||
7 | +exports.Strategy = Strategy_1.default; | ||
8 | +exports.default = Strategy_1.default; |
1 | +(The MIT License) | ||
2 | + | ||
3 | +Copyright (c) 2011-2014 Jared Hanson | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
6 | +this software and associated documentation files (the "Software"), to deal in | ||
7 | +the Software without restriction, including without limitation the rights to | ||
8 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
9 | +the Software, and to permit persons to whom the Software is furnished to do so, | ||
10 | +subject to the following conditions: | ||
11 | + | ||
12 | +The above copyright notice and this permission notice shall be included in all | ||
13 | +copies or substantial portions of the Software. | ||
14 | + | ||
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
17 | +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
18 | +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
19 | +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
20 | +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
1 | +# passport-oauth2 | ||
2 | + | ||
3 | +[](https://travis-ci.org/jaredhanson/passport-oauth2) | ||
4 | +[](https://coveralls.io/r/jaredhanson/passport-oauth2) | ||
5 | +[](https://codeclimate.com/github/jaredhanson/passport-oauth2) | ||
6 | +[](https://david-dm.org/jaredhanson/passport-oauth2) | ||
7 | +[](https://www.gittip.com/jaredhanson/) | ||
8 | + | ||
9 | +General-purpose OAuth 2.0 authentication strategy for [Passport](http://passportjs.org/). | ||
10 | + | ||
11 | +This module lets you authenticate using OAuth 2.0 in your Node.js applications. | ||
12 | +By plugging into Passport, OAuth 2.0 authentication can be easily and | ||
13 | +unobtrusively integrated into any application or framework that supports | ||
14 | +[Connect](http://www.senchalabs.org/connect/)-style middleware, including | ||
15 | +[Express](http://expressjs.com/). | ||
16 | + | ||
17 | +Note that this strategy provides generic OAuth 2.0 support. In many cases, a | ||
18 | +provider-specific strategy can be used instead, which cuts down on unnecessary | ||
19 | +configuration, and accommodates any provider-specific quirks. See the | ||
20 | +[list](https://github.com/jaredhanson/passport/wiki/Strategies) for supported | ||
21 | +providers. | ||
22 | + | ||
23 | +Developers who need to implement authentication against an OAuth 2.0 provider | ||
24 | +that is not already supported are encouraged to sub-class this strategy. If you | ||
25 | +choose to open source the new provider-specific strategy, please add it to the | ||
26 | +list so other people can find it. | ||
27 | + | ||
28 | +## Install | ||
29 | + | ||
30 | + $ npm install passport-oauth2 | ||
31 | + | ||
32 | +## Usage | ||
33 | + | ||
34 | +#### Configure Strategy | ||
35 | + | ||
36 | +The OAuth 2.0 authentication strategy authenticates users using a third-party | ||
37 | +account and OAuth 2.0 tokens. The provider's OAuth 2.0 endpoints, as well as | ||
38 | +the client identifer and secret, are specified as options. The strategy | ||
39 | +requires a `verify` callback, which receives an access token and profile, | ||
40 | +and calls `done` providing a user. | ||
41 | + | ||
42 | + passport.use(new OAuth2Strategy({ | ||
43 | + authorizationURL: 'https://www.example.com/oauth2/authorize', | ||
44 | + tokenURL: 'https://www.example.com/oauth2/token', | ||
45 | + clientID: EXAMPLE_CLIENT_ID, | ||
46 | + clientSecret: EXAMPLE_CLIENT_SECRET, | ||
47 | + callbackURL: "http://localhost:3000/auth/example/callback" | ||
48 | + }, | ||
49 | + function(accessToken, refreshToken, profile, done) { | ||
50 | + User.findOrCreate({ exampleId: profile.id }, function (err, user) { | ||
51 | + return done(err, user); | ||
52 | + }); | ||
53 | + } | ||
54 | + )); | ||
55 | + | ||
56 | +#### Authenticate Requests | ||
57 | + | ||
58 | +Use `passport.authenticate()`, specifying the `'oauth2'` strategy, to | ||
59 | +authenticate requests. | ||
60 | + | ||
61 | +For example, as route middleware in an [Express](http://expressjs.com/) | ||
62 | +application: | ||
63 | + | ||
64 | + app.get('/auth/example', | ||
65 | + passport.authenticate('oauth2')); | ||
66 | + | ||
67 | + app.get('/auth/example/callback', | ||
68 | + passport.authenticate('oauth2', { failureRedirect: '/login' }), | ||
69 | + function(req, res) { | ||
70 | + // Successful authentication, redirect home. | ||
71 | + res.redirect('/'); | ||
72 | + }); | ||
73 | + | ||
74 | +## Related Modules | ||
75 | + | ||
76 | +- [passport-oauth1](https://github.com/jaredhanson/passport-oauth1) — OAuth 1.0 authentication strategy | ||
77 | +- [passport-http-bearer](https://github.com/jaredhanson/passport-http-bearer) — Bearer token authentication strategy for APIs | ||
78 | +- [OAuth2orize](https://github.com/jaredhanson/oauth2orize) — OAuth 2.0 authorization server toolkit | ||
79 | + | ||
80 | +## Tests | ||
81 | + | ||
82 | + $ npm install | ||
83 | + $ npm test | ||
84 | + | ||
85 | +## Credits | ||
86 | + | ||
87 | + - [Jared Hanson](http://github.com/jaredhanson) | ||
88 | + | ||
89 | +## License | ||
90 | + | ||
91 | +[The MIT License](http://opensource.org/licenses/MIT) | ||
92 | + | ||
93 | +Copyright (c) 2011-2014 Jared Hanson <[http://jaredhanson.net/](http://jaredhanson.net/)> |
node_modules/passport-kakao/node_modules/passport-oauth2/lib/errors/authorizationerror.js
0 → 100644
1 | +/** | ||
2 | + * `AuthorizationError` error. | ||
3 | + * | ||
4 | + * AuthorizationError represents an error in response to an authorization | ||
5 | + * request. For details, refer to RFC 6749, section 4.1.2.1. | ||
6 | + * | ||
7 | + * References: | ||
8 | + * - [The OAuth 2.0 Authorization Framework](http://tools.ietf.org/html/rfc6749) | ||
9 | + * | ||
10 | + * @constructor | ||
11 | + * @param {String} [message] | ||
12 | + * @param {String} [code] | ||
13 | + * @param {String} [uri] | ||
14 | + * @param {Number} [status] | ||
15 | + * @api public | ||
16 | + */ | ||
17 | +function AuthorizationError(message, code, uri, status) { | ||
18 | + if (!status) { | ||
19 | + switch (code) { | ||
20 | + case 'access_denied': status = 403; break; | ||
21 | + case 'server_error': status = 502; break; | ||
22 | + case 'temporarily_unavailable': status = 503; break; | ||
23 | + } | ||
24 | + } | ||
25 | + | ||
26 | + Error.call(this); | ||
27 | + Error.captureStackTrace(this, arguments.callee); | ||
28 | + this.name = 'AuthorizationError'; | ||
29 | + this.message = message; | ||
30 | + this.code = code || 'server_error'; | ||
31 | + this.uri = uri; | ||
32 | + this.status = status || 500; | ||
33 | +} | ||
34 | + | ||
35 | +/** | ||
36 | + * Inherit from `Error`. | ||
37 | + */ | ||
38 | +AuthorizationError.prototype.__proto__ = Error.prototype; | ||
39 | + | ||
40 | + | ||
41 | +/** | ||
42 | + * Expose `AuthorizationError`. | ||
43 | + */ | ||
44 | +module.exports = AuthorizationError; |
node_modules/passport-kakao/node_modules/passport-oauth2/lib/errors/internaloautherror.js
0 → 100644
1 | +/** | ||
2 | + * `InternalOAuthError` error. | ||
3 | + * | ||
4 | + * InternalOAuthError wraps errors generated by node-oauth. By wrapping these | ||
5 | + * objects, error messages can be formatted in a manner that aids in debugging | ||
6 | + * OAuth issues. | ||
7 | + * | ||
8 | + * @constructor | ||
9 | + * @param {String} [message] | ||
10 | + * @param {Object|Error} [err] | ||
11 | + * @api public | ||
12 | + */ | ||
13 | +function InternalOAuthError(message, err) { | ||
14 | + Error.call(this); | ||
15 | + Error.captureStackTrace(this, arguments.callee); | ||
16 | + this.name = 'InternalOAuthError'; | ||
17 | + this.message = message; | ||
18 | + this.oauthError = err; | ||
19 | +} | ||
20 | + | ||
21 | +/** | ||
22 | + * Inherit from `Error`. | ||
23 | + */ | ||
24 | +InternalOAuthError.prototype.__proto__ = Error.prototype; | ||
25 | + | ||
26 | +/** | ||
27 | + * Returns a string representing the error. | ||
28 | + * | ||
29 | + * @return {String} | ||
30 | + * @api public | ||
31 | + */ | ||
32 | +InternalOAuthError.prototype.toString = function() { | ||
33 | + var m = this.name; | ||
34 | + if (this.message) { m += ': ' + this.message; } | ||
35 | + if (this.oauthError) { | ||
36 | + if (this.oauthError instanceof Error) { | ||
37 | + m = this.oauthError.toString(); | ||
38 | + } else if (this.oauthError.statusCode && this.oauthError.data) { | ||
39 | + m += ' (status: ' + this.oauthError.statusCode + ' data: ' + this.oauthError.data + ')'; | ||
40 | + } | ||
41 | + } | ||
42 | + return m; | ||
43 | +}; | ||
44 | + | ||
45 | + | ||
46 | +/** | ||
47 | + * Expose `InternalOAuthError`. | ||
48 | + */ | ||
49 | +module.exports = InternalOAuthError; |
1 | +/** | ||
2 | + * `TokenError` error. | ||
3 | + * | ||
4 | + * TokenError represents an error received from a token endpoint. For details, | ||
5 | + * refer to RFC 6749, section 5.2. | ||
6 | + * | ||
7 | + * References: | ||
8 | + * - [The OAuth 2.0 Authorization Framework](http://tools.ietf.org/html/rfc6749) | ||
9 | + * | ||
10 | + * @constructor | ||
11 | + * @param {String} [message] | ||
12 | + * @param {String} [code] | ||
13 | + * @param {String} [uri] | ||
14 | + * @param {Number} [status] | ||
15 | + * @api public | ||
16 | + */ | ||
17 | +function TokenError(message, code, uri, status) { | ||
18 | + Error.call(this); | ||
19 | + Error.captureStackTrace(this, arguments.callee); | ||
20 | + this.name = 'TokenError'; | ||
21 | + this.message = message; | ||
22 | + this.code = code || 'invalid_request'; | ||
23 | + this.uri = uri; | ||
24 | + this.status = status || 500; | ||
25 | +} | ||
26 | + | ||
27 | +/** | ||
28 | + * Inherit from `Error`. | ||
29 | + */ | ||
30 | +TokenError.prototype.__proto__ = Error.prototype; | ||
31 | + | ||
32 | + | ||
33 | +/** | ||
34 | + * Expose `TokenError`. | ||
35 | + */ | ||
36 | +module.exports = TokenError; |
1 | +/** | ||
2 | + * Module dependencies. | ||
3 | + */ | ||
4 | +var Strategy = require('./strategy') | ||
5 | + , AuthorizationError = require('./errors/authorizationerror') | ||
6 | + , TokenError = require('./errors/tokenerror') | ||
7 | + , InternalOAuthError = require('./errors/internaloautherror'); | ||
8 | + | ||
9 | + | ||
10 | +/** | ||
11 | + * Expose `Strategy` directly from package. | ||
12 | + */ | ||
13 | +exports = module.exports = Strategy; | ||
14 | + | ||
15 | +/** | ||
16 | + * Export constructors. | ||
17 | + */ | ||
18 | +exports.Strategy = Strategy; | ||
19 | + | ||
20 | +/** | ||
21 | + * Export errors. | ||
22 | + */ | ||
23 | +exports.AuthorizationError = AuthorizationError; | ||
24 | +exports.TokenError = TokenError; | ||
25 | +exports.InternalOAuthError = InternalOAuthError; |
This diff is collapsed. Click to expand it.
1 | +/** | ||
2 | + * Reconstructs the original URL of the request. | ||
3 | + * | ||
4 | + * This function builds a URL that corresponds the original URL requested by the | ||
5 | + * client, including the protocol (http or https) and host. | ||
6 | + * | ||
7 | + * If the request passed through any proxies that terminate SSL, the | ||
8 | + * `X-Forwarded-Proto` header is used to detect if the request was encrypted to | ||
9 | + * the proxy, assuming that the proxy has been flagged as trusted. | ||
10 | + * | ||
11 | + * @param {http.IncomingMessage} req | ||
12 | + * @param {Object} [options] | ||
13 | + * @return {String} | ||
14 | + * @api private | ||
15 | + */ | ||
16 | +exports.originalURL = function(req, options) { | ||
17 | + options = options || {}; | ||
18 | + var app = req.app; | ||
19 | + if (app && app.get && app.get('trust proxy')) { | ||
20 | + options.proxy = true; | ||
21 | + } | ||
22 | + var trustProxy = options.proxy; | ||
23 | + | ||
24 | + var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase() | ||
25 | + , tls = req.connection.encrypted || (trustProxy && 'https' == proto.split(/\s*,\s*/)[0]) | ||
26 | + , host = (trustProxy && req.headers['x-forwarded-host']) || req.headers.host | ||
27 | + , protocol = tls ? 'https' : 'http' | ||
28 | + , path = req.url || ''; | ||
29 | + return protocol + '://' + host + path; | ||
30 | +}; |
1 | +{ | ||
2 | + "name": "passport-oauth2", | ||
3 | + "version": "1.1.2", | ||
4 | + "description": "OAuth 2.0 authentication strategy for Passport.", | ||
5 | + "keywords": [ | ||
6 | + "passport", | ||
7 | + "auth", | ||
8 | + "authn", | ||
9 | + "authentication", | ||
10 | + "authz", | ||
11 | + "authorization", | ||
12 | + "oauth", | ||
13 | + "oauth2" | ||
14 | + ], | ||
15 | + "author": { | ||
16 | + "name": "Jared Hanson", | ||
17 | + "email": "jaredhanson@gmail.com", | ||
18 | + "url": "http://www.jaredhanson.net/" | ||
19 | + }, | ||
20 | + "repository": { | ||
21 | + "type": "git", | ||
22 | + "url": "git://github.com/jaredhanson/passport-oauth2.git" | ||
23 | + }, | ||
24 | + "bugs": { | ||
25 | + "url": "http://github.com/jaredhanson/passport-oauth2/issues" | ||
26 | + }, | ||
27 | + "licenses": [ | ||
28 | + { | ||
29 | + "type": "MIT", | ||
30 | + "url": "http://www.opensource.org/licenses/MIT" | ||
31 | + } | ||
32 | + ], | ||
33 | + "main": "./lib", | ||
34 | + "dependencies": { | ||
35 | + "passport-strategy": "1.x.x", | ||
36 | + "oauth": "0.9.x", | ||
37 | + "uid2": "0.0.x" | ||
38 | + }, | ||
39 | + "devDependencies": { | ||
40 | + "mocha": "1.x.x", | ||
41 | + "chai": "1.x.x", | ||
42 | + "chai-passport-strategy": "0.2.x" | ||
43 | + }, | ||
44 | + "engines": { | ||
45 | + "node": ">= 0.4.0" | ||
46 | + }, | ||
47 | + "scripts": { | ||
48 | + "test": "node_modules/.bin/mocha --reporter spec --require test/bootstrap/node test/*.test.js test/**/*.test.js" | ||
49 | + } | ||
50 | +} |
node_modules/passport-kakao/package.json
0 → 100644
1 | +{ | ||
2 | + "name": "passport-kakao", | ||
3 | + "version": "1.0.1", | ||
4 | + "description": "kakao oauth2 login module", | ||
5 | + "main": "./dist/passport-kakao", | ||
6 | + "keywords": [ | ||
7 | + "passport", | ||
8 | + "kakao", | ||
9 | + "kakaotalk", | ||
10 | + "oauth2" | ||
11 | + ], | ||
12 | + "repository": { | ||
13 | + "type": "git", | ||
14 | + "url": "git://github.com/rotoshine/passport-kakao.git" | ||
15 | + }, | ||
16 | + "author": "rotoshine@gmail.com", | ||
17 | + "license": "MIT", | ||
18 | + "dependencies": { | ||
19 | + "pkginfo": "~0.3.0", | ||
20 | + "passport-oauth2": "~1.1.2" | ||
21 | + }, | ||
22 | + "devDependencies": { | ||
23 | + "@types/chai": "^4.2.3", | ||
24 | + "@types/mocha": "^5.2.7", | ||
25 | + "@types/node": "^12.7.11", | ||
26 | + "@typescript-eslint/eslint-plugin": "^2.30.0", | ||
27 | + "@typescript-eslint/parser": "^2.30.0", | ||
28 | + "chai": "^4.2.0", | ||
29 | + "eslint": "^6.8.0", | ||
30 | + "mocha": "^6.2.1", | ||
31 | + "prettier": "^2.0.5", | ||
32 | + "rimraf": "^3.0.2", | ||
33 | + "ts-node": "^8.4.1", | ||
34 | + "tslint": "^5.20.0", | ||
35 | + "tslint-config-prettier": "^1.18.0", | ||
36 | + "typescript": "^3.6.3" | ||
37 | + }, | ||
38 | + "scripts": { | ||
39 | + "test": "mocha -r node_modules/ts-node/register ./tests/**/*.spec.ts", | ||
40 | + "clean": "rimraf dist/*", | ||
41 | + "build": "npm run clean && npx tsc", | ||
42 | + "lint": "eslint -c .eslintrc.js src/**/*.ts", | ||
43 | + "format": "prettier --write \"src/*.{ts,tsx,json,md}\"" | ||
44 | + } | ||
45 | +} |
node_modules/passport-kakao/sample/README.md
0 → 100644
This diff is collapsed. Click to expand it.
node_modules/passport-kakao/sample/sample.js
0 → 100644
1 | +require('dotenv').config() | ||
2 | + | ||
3 | +const passport = require('passport') | ||
4 | +const express = require('express') | ||
5 | +const KakaoStrategy = require('../dist/passport-kakao.js').Strategy | ||
6 | + | ||
7 | +const appKey = process.env.API_KEY | ||
8 | +const appSecret = process.env.CLIENT_SECRET_KEY | ||
9 | + | ||
10 | +// passport 에 Kakao Oauth 추가 | ||
11 | +passport.use( | ||
12 | + new KakaoStrategy( | ||
13 | + { | ||
14 | + clientID: appKey, | ||
15 | + clientSecret: appSecret, | ||
16 | + callbackURL: 'http://localhost:3000/oauth', | ||
17 | + }, | ||
18 | + function (accessToken, refreshToken, params, profile, done) { | ||
19 | + // authorization 에 성공했을때의 액션 | ||
20 | + console.log(`accessToken : ${accessToken}`) | ||
21 | + console.log(`사용자 profile: ${JSON.stringify(profile._json)}`) | ||
22 | + | ||
23 | + save(accessToken, refreshToken, profile) | ||
24 | + return done(null, profile._json) | ||
25 | + } | ||
26 | + ) | ||
27 | +) | ||
28 | +passport.serializeUser(function (user, done) { | ||
29 | + done(null, user) | ||
30 | +}) | ||
31 | +passport.deserializeUser(function (obj, done) { | ||
32 | + done(null, obj) | ||
33 | +}) | ||
34 | + | ||
35 | +// express 앱 설정 | ||
36 | +var app = express() | ||
37 | +app.use(passport.initialize()) | ||
38 | +app.get('/login', passport.authenticate('kakao', { state: 'myStateValue' })) | ||
39 | +app.get('/oauth', passport.authenticate('kakao'), function (req, res) { | ||
40 | + // 로그인 시작시 state 값을 받을 수 있음 | ||
41 | + res.send('state :' + req.query.state) | ||
42 | +}) | ||
43 | +app.listen(3000) | ||
44 | +console.log('> server start! ') | ||
45 | + | ||
46 | +// 사용자 구현 부분 | ||
47 | +function save() { | ||
48 | + //save 로직 구현 | ||
49 | +} |
node_modules/passport-kakao/src/Strategy.ts
0 → 100644
1 | +import { inherits } from 'util' | ||
2 | +import OAuth2Strategy from 'passport-oauth2' | ||
3 | + | ||
4 | +import { StrategyOptions, Profile } from './types/models' | ||
5 | + | ||
6 | +const DEFAULT_CLIENT_SECRET = 'kakao' | ||
7 | +const OAUTH_HOST = 'https://kauth.kakao.com' | ||
8 | +const USER_PROFILE_URL = 'https://kapi.kakao.com/v2/user/me' | ||
9 | + | ||
10 | +export const buildOptions = (options: StrategyOptions) => { | ||
11 | + options.authorizationURL = `${OAUTH_HOST}/oauth/authorize` | ||
12 | + options.tokenURL = `${OAUTH_HOST}/oauth/token` | ||
13 | + | ||
14 | + if (!options.clientSecret) { | ||
15 | + options.clientSecret = DEFAULT_CLIENT_SECRET | ||
16 | + } | ||
17 | + | ||
18 | + options.scopeSeparator = options.scopeSeparator || ',' | ||
19 | + options.customHeaders = options.customHeaders || {} | ||
20 | + | ||
21 | + if (!options.customHeaders['User-Agent']) { | ||
22 | + options.customHeaders['User-Agent'] = options.userAgent || 'passport-kakao' | ||
23 | + } | ||
24 | + | ||
25 | + return options | ||
26 | +} | ||
27 | +/** | ||
28 | + * KaKaoStrategy 생성자 함수.<br/> | ||
29 | + * @param options.clientID 필수. kakao rest app key. | ||
30 | + * @param options.callbackURL 필수. 로그인 처리 후 호출할 URL | ||
31 | + * @param verify | ||
32 | + * @constructor | ||
33 | + */ | ||
34 | +function Strategy(options: StrategyOptions = {}, verify: any) { | ||
35 | + OAuth2Strategy.call(this, buildOptions(options), verify) | ||
36 | + this.name = 'kakao' | ||
37 | + this._userProfileURL = USER_PROFILE_URL | ||
38 | +} | ||
39 | + | ||
40 | +/** | ||
41 | + * `OAuth2Stragegy`를 상속 받는다. | ||
42 | + */ | ||
43 | +inherits(Strategy, OAuth2Strategy) | ||
44 | + | ||
45 | +/** | ||
46 | + * kakao 사용자 정보를 얻는다.<br/> | ||
47 | + * 사용자 정보를 성공적으로 조회하면 아래의 object가 done 콜백함수 호출과 함꼐 넘어간다. | ||
48 | + * | ||
49 | + * - `provider` kakao 고정 | ||
50 | + * - `id` kakao user id number | ||
51 | + * - `username` 사용자의 kakao nickname | ||
52 | + * - `_raw` json string 원문 | ||
53 | + * _ `_json` json 원 데이터 | ||
54 | + * | ||
55 | + * @param {String} accessToken | ||
56 | + * @param {Function} done | ||
57 | + */ | ||
58 | +Strategy.prototype.userProfile = function ( | ||
59 | + accessToken: string, | ||
60 | + done: (error: Error, profile?: Profile) => void | ||
61 | +) { | ||
62 | + this._oauth2.get( | ||
63 | + this._userProfileURL, | ||
64 | + accessToken, | ||
65 | + (err: Error, body: string) => { | ||
66 | + if (err) { | ||
67 | + return done(err) | ||
68 | + } | ||
69 | + | ||
70 | + try { | ||
71 | + const json = JSON.parse(body) | ||
72 | + // 카카오톡이나 카카오스토리에 연동한 적이 없는 계정의 경우 | ||
73 | + // properties가 비어있다고 한다. 없을 경우의 처리 | ||
74 | + const properties = json.properties || { | ||
75 | + nickname: '미연동 계정', | ||
76 | + } | ||
77 | + const profile: Profile = { | ||
78 | + provider: 'kakao', | ||
79 | + id: json.id, | ||
80 | + username: properties.nickname, | ||
81 | + displayName: properties.nickname, | ||
82 | + _raw: body, | ||
83 | + _json: json, | ||
84 | + } | ||
85 | + return done(null, profile) | ||
86 | + } catch (e) { | ||
87 | + return done(e) | ||
88 | + } | ||
89 | + } | ||
90 | + ) | ||
91 | +} | ||
92 | + | ||
93 | +export default Strategy |
1 | +export interface StrategyOptions { | ||
2 | + authorizationURL?: string | ||
3 | + tokenURL?: string | ||
4 | + clientSecret?: string | ||
5 | + scopeSeparator?: string | ||
6 | + customHeaders?: { | ||
7 | + 'User-Agent'?: string | ||
8 | + } | ||
9 | + userAgent?: string | ||
10 | +} | ||
11 | + | ||
12 | +export interface Profile { | ||
13 | + provider: 'kakao' | ||
14 | + id?: string | number | ||
15 | + username?: string | ||
16 | + displayName?: string | ||
17 | + _raw: string | ||
18 | + _json: string | ||
19 | +} |
1 | +import { expect } from 'chai' | ||
2 | +import KakaoStrategy, { buildOptions } from '../src/Strategy' | ||
3 | + | ||
4 | +describe('passport-kakao', () => { | ||
5 | + it('passport-kakao 객체가 제대로 생성이 되어 있어야 한다.', () => { | ||
6 | + expect(KakaoStrategy).to.not.equals(null) | ||
7 | + }) | ||
8 | + it('Strategy option의 clientSecret 값이 없을 경우 default 값이 설정되어야 한다.', () => { | ||
9 | + const options = buildOptions({}) | ||
10 | + | ||
11 | + expect(options).to.not.equals(null) | ||
12 | + expect(options.clientSecret).to.be.equals('kakao') | ||
13 | + expect(options.scopeSeparator).to.be.equals(',') | ||
14 | + expect(options.customHeaders['User-Agent']).to.be.equals('passport-kakao') | ||
15 | + }) | ||
16 | + it('Strategy option의 User-Agent값이 있을 경우 customHeaders의 User-Agent가 해당 값으로 설정되어야 한다.', () => { | ||
17 | + const options = buildOptions({ | ||
18 | + customHeaders: { | ||
19 | + 'User-Agent': 'HELLO ROTO', | ||
20 | + }, | ||
21 | + }) | ||
22 | + expect(options.customHeaders['User-Agent']).to.be.equals('HELLO ROTO') | ||
23 | + }) | ||
24 | +}) |
node_modules/passport-kakao/tsconfig.json
0 → 100644
1 | +{ | ||
2 | + "include": ["./src"], | ||
3 | + "compilerOptions": { | ||
4 | + /* Basic Options */ | ||
5 | + // "incremental": true, /* Enable incremental compilation */ | ||
6 | + "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, | ||
7 | + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, | ||
8 | + // "lib": [], /* Specify library files to be included in the compilation. */ | ||
9 | + // "allowJs": true, /* Allow javascript files to be compiled. */ | ||
10 | + // "checkJs": true, /* Report errors in .js files. */ | ||
11 | + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ | ||
12 | + // "declaration": true, /* Generates corresponding '.d.ts' file. */ | ||
13 | + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ | ||
14 | + // "sourceMap": true, /* Generates corresponding '.map' file. */ | ||
15 | + // "outFile": "./", /* Concatenate and emit output to single file. */ | ||
16 | + "outDir": "./dist" /* Redirect output structure to the directory. */, | ||
17 | + "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, | ||
18 | + // "composite": true, /* Enable project compilation */ | ||
19 | + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ | ||
20 | + // "removeComments": true, /* Do not emit comments to output. */ | ||
21 | + // "noEmit": true, /* Do not emit outputs. */ | ||
22 | + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ | ||
23 | + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ | ||
24 | + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ | ||
25 | + | ||
26 | + /* Strict Type-Checking Options */ | ||
27 | + "strict": false /* Enable all strict type-checking options. */, | ||
28 | + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ | ||
29 | + // "strictNullChecks": true, /* Enable strict null checks. */ | ||
30 | + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ | ||
31 | + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ | ||
32 | + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ | ||
33 | + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ | ||
34 | + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ | ||
35 | + | ||
36 | + /* Additional Checks */ | ||
37 | + // "noUnusedLocals": true, /* Report errors on unused locals. */ | ||
38 | + // "noUnusedParameters": true, /* Report errors on unused parameters. */ | ||
39 | + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ | ||
40 | + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ | ||
41 | + | ||
42 | + /* Module Resolution Options */ | ||
43 | + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ | ||
44 | + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ | ||
45 | + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ | ||
46 | + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ | ||
47 | + // "typeRoots": [], /* List of folders to include type definitions from. */ | ||
48 | + // "types": [], /* Type declaration files to be included in compilation. */ | ||
49 | + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ | ||
50 | + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ | ||
51 | + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ | ||
52 | + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ | ||
53 | + | ||
54 | + /* Source Map Options */ | ||
55 | + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ | ||
56 | + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ | ||
57 | + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ | ||
58 | + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ | ||
59 | + | ||
60 | + /* Experimental Options */ | ||
61 | + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ | ||
62 | + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ | ||
63 | + } | ||
64 | +} |
node_modules/pkginfo/.npmignore
0 → 100644
node_modules/pkginfo/LICENSE
0 → 100644
1 | +Copyright (c) 2010 Charlie Robbins. | ||
2 | + | ||
3 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | +of this software and associated documentation files (the "Software"), to deal | ||
5 | +in the Software without restriction, including without limitation the rights | ||
6 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | +copies of the Software, and to permit persons to whom the Software is | ||
8 | +furnished to do so, subject to the following conditions: | ||
9 | + | ||
10 | +The above copyright notice and this permission notice shall be included in | ||
11 | +all copies or substantial portions of the Software. | ||
12 | + | ||
13 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
19 | +THE SOFTWARE. | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
node_modules/pkginfo/README.md
0 → 100644
1 | +# node-pkginfo | ||
2 | + | ||
3 | +An easy way to expose properties on a module from a package.json | ||
4 | + | ||
5 | +## Installation | ||
6 | + | ||
7 | +### Installing npm (node package manager) | ||
8 | +``` | ||
9 | + curl http://npmjs.org/install.sh | sh | ||
10 | +``` | ||
11 | + | ||
12 | +### Installing pkginfo | ||
13 | +``` | ||
14 | + [sudo] npm install pkginfo | ||
15 | +``` | ||
16 | + | ||
17 | +## Motivation | ||
18 | +How often when writing node.js modules have you written the following line(s) of code? | ||
19 | + | ||
20 | +* Hard code your version string into your code | ||
21 | + | ||
22 | +``` js | ||
23 | + exports.version = '0.1.0'; | ||
24 | +``` | ||
25 | + | ||
26 | +* Programmatically expose the version from the package.json | ||
27 | + | ||
28 | +``` js | ||
29 | + exports.version = require('/path/to/package.json').version; | ||
30 | +``` | ||
31 | + | ||
32 | +In other words, how often have you wanted to expose basic information from your package.json onto your module programmatically? **WELL NOW YOU CAN!** | ||
33 | + | ||
34 | +## Usage | ||
35 | + | ||
36 | +Using `pkginfo` is idiot-proof, just require and invoke it. | ||
37 | + | ||
38 | +``` js | ||
39 | + var pkginfo = require('pkginfo')(module); | ||
40 | + | ||
41 | + console.dir(module.exports); | ||
42 | +``` | ||
43 | + | ||
44 | +By invoking the `pkginfo` module all of the properties in your `package.json` file will be automatically exposed on the callee module (i.e. the parent module of `pkginfo`). | ||
45 | + | ||
46 | +Here's a sample of the output: | ||
47 | + | ||
48 | +``` | ||
49 | + { name: 'simple-app', | ||
50 | + description: 'A test fixture for pkginfo', | ||
51 | + version: '0.1.0', | ||
52 | + author: 'Charlie Robbins <charlie.robbins@gmail.com>', | ||
53 | + keywords: [ 'test', 'fixture' ], | ||
54 | + main: './index.js', | ||
55 | + scripts: { test: 'vows test/*-test.js --spec' }, | ||
56 | + engines: { node: '>= 0.4.0' } } | ||
57 | +``` | ||
58 | + | ||
59 | +### Expose specific properties | ||
60 | +If you don't want to expose **all** properties on from your `package.json` on your module then simple pass those properties to the `pkginfo` function: | ||
61 | + | ||
62 | +``` js | ||
63 | + var pkginfo = require('pkginfo')(module, 'version', 'author'); | ||
64 | + | ||
65 | + console.dir(module.exports); | ||
66 | +``` | ||
67 | + | ||
68 | +``` | ||
69 | + { version: '0.1.0', | ||
70 | + author: 'Charlie Robbins <charlie.robbins@gmail.com>' } | ||
71 | +``` | ||
72 | + | ||
73 | +If you're looking for further usage see the [examples][0] included in this repository. | ||
74 | + | ||
75 | +## Run Tests | ||
76 | +Tests are written in [vows][1] and give complete coverage of all APIs. | ||
77 | + | ||
78 | +``` | ||
79 | + vows test/*-test.js --spec | ||
80 | +``` | ||
81 | + | ||
82 | +[0]: https://github.com/indexzero/node-pkginfo/tree/master/examples | ||
83 | +[1]: http://vowsjs.org | ||
84 | + | ||
85 | +#### Author: [Charlie Robbins](http://nodejitsu.com) | ||
86 | +#### License: MIT |
node_modules/pkginfo/docs/docco.css
0 → 100644
1 | +/*--------------------- Layout and Typography ----------------------------*/ | ||
2 | +body { | ||
3 | + font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; | ||
4 | + font-size: 15px; | ||
5 | + line-height: 22px; | ||
6 | + color: #252519; | ||
7 | + margin: 0; padding: 0; | ||
8 | +} | ||
9 | +a { | ||
10 | + color: #261a3b; | ||
11 | +} | ||
12 | + a:visited { | ||
13 | + color: #261a3b; | ||
14 | + } | ||
15 | +p { | ||
16 | + margin: 0 0 15px 0; | ||
17 | +} | ||
18 | +h4, h5, h6 { | ||
19 | + color: #333; | ||
20 | + margin: 6px 0 6px 0; | ||
21 | + font-size: 13px; | ||
22 | +} | ||
23 | + h2, h3 { | ||
24 | + margin-bottom: 0; | ||
25 | + color: #000; | ||
26 | + } | ||
27 | + h1 { | ||
28 | + margin-top: 40px; | ||
29 | + margin-bottom: 15px; | ||
30 | + color: #000; | ||
31 | + } | ||
32 | +#container { | ||
33 | + position: relative; | ||
34 | +} | ||
35 | +#background { | ||
36 | + position: fixed; | ||
37 | + top: 0; left: 525px; right: 0; bottom: 0; | ||
38 | + background: #f5f5ff; | ||
39 | + border-left: 1px solid #e5e5ee; | ||
40 | + z-index: -1; | ||
41 | +} | ||
42 | +#jump_to, #jump_page { | ||
43 | + background: white; | ||
44 | + -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; | ||
45 | + -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; | ||
46 | + font: 10px Arial; | ||
47 | + text-transform: uppercase; | ||
48 | + cursor: pointer; | ||
49 | + text-align: right; | ||
50 | +} | ||
51 | +#jump_to, #jump_wrapper { | ||
52 | + position: fixed; | ||
53 | + right: 0; top: 0; | ||
54 | + padding: 5px 10px; | ||
55 | +} | ||
56 | + #jump_wrapper { | ||
57 | + padding: 0; | ||
58 | + display: none; | ||
59 | + } | ||
60 | + #jump_to:hover #jump_wrapper { | ||
61 | + display: block; | ||
62 | + } | ||
63 | + #jump_page { | ||
64 | + padding: 5px 0 3px; | ||
65 | + margin: 0 0 25px 25px; | ||
66 | + } | ||
67 | + #jump_page .source { | ||
68 | + display: block; | ||
69 | + padding: 5px 10px; | ||
70 | + text-decoration: none; | ||
71 | + border-top: 1px solid #eee; | ||
72 | + } | ||
73 | + #jump_page .source:hover { | ||
74 | + background: #f5f5ff; | ||
75 | + } | ||
76 | + #jump_page .source:first-child { | ||
77 | + } | ||
78 | +table td { | ||
79 | + border: 0; | ||
80 | + outline: 0; | ||
81 | +} | ||
82 | + td.docs, th.docs { | ||
83 | + max-width: 450px; | ||
84 | + min-width: 450px; | ||
85 | + min-height: 5px; | ||
86 | + padding: 10px 25px 1px 50px; | ||
87 | + overflow-x: hidden; | ||
88 | + vertical-align: top; | ||
89 | + text-align: left; | ||
90 | + } | ||
91 | + .docs pre { | ||
92 | + margin: 15px 0 15px; | ||
93 | + padding-left: 15px; | ||
94 | + } | ||
95 | + .docs p tt, .docs p code { | ||
96 | + background: #f8f8ff; | ||
97 | + border: 1px solid #dedede; | ||
98 | + font-size: 12px; | ||
99 | + padding: 0 0.2em; | ||
100 | + } | ||
101 | + .pilwrap { | ||
102 | + position: relative; | ||
103 | + } | ||
104 | + .pilcrow { | ||
105 | + font: 12px Arial; | ||
106 | + text-decoration: none; | ||
107 | + color: #454545; | ||
108 | + position: absolute; | ||
109 | + top: 3px; left: -20px; | ||
110 | + padding: 1px 2px; | ||
111 | + opacity: 0; | ||
112 | + -webkit-transition: opacity 0.2s linear; | ||
113 | + } | ||
114 | + td.docs:hover .pilcrow { | ||
115 | + opacity: 1; | ||
116 | + } | ||
117 | + td.code, th.code { | ||
118 | + padding: 14px 15px 16px 25px; | ||
119 | + width: 100%; | ||
120 | + vertical-align: top; | ||
121 | + background: #f5f5ff; | ||
122 | + border-left: 1px solid #e5e5ee; | ||
123 | + } | ||
124 | + pre, tt, code { | ||
125 | + font-size: 12px; line-height: 18px; | ||
126 | + font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; | ||
127 | + margin: 0; padding: 0; | ||
128 | + } | ||
129 | + | ||
130 | + | ||
131 | +/*---------------------- Syntax Highlighting -----------------------------*/ | ||
132 | +td.linenos { background-color: #f0f0f0; padding-right: 10px; } | ||
133 | +span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } | ||
134 | +body .hll { background-color: #ffffcc } | ||
135 | +body .c { color: #408080; font-style: italic } /* Comment */ | ||
136 | +body .err { border: 1px solid #FF0000 } /* Error */ | ||
137 | +body .k { color: #954121 } /* Keyword */ | ||
138 | +body .o { color: #666666 } /* Operator */ | ||
139 | +body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ | ||
140 | +body .cp { color: #BC7A00 } /* Comment.Preproc */ | ||
141 | +body .c1 { color: #408080; font-style: italic } /* Comment.Single */ | ||
142 | +body .cs { color: #408080; font-style: italic } /* Comment.Special */ | ||
143 | +body .gd { color: #A00000 } /* Generic.Deleted */ | ||
144 | +body .ge { font-style: italic } /* Generic.Emph */ | ||
145 | +body .gr { color: #FF0000 } /* Generic.Error */ | ||
146 | +body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ | ||
147 | +body .gi { color: #00A000 } /* Generic.Inserted */ | ||
148 | +body .go { color: #808080 } /* Generic.Output */ | ||
149 | +body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ | ||
150 | +body .gs { font-weight: bold } /* Generic.Strong */ | ||
151 | +body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ | ||
152 | +body .gt { color: #0040D0 } /* Generic.Traceback */ | ||
153 | +body .kc { color: #954121 } /* Keyword.Constant */ | ||
154 | +body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ | ||
155 | +body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ | ||
156 | +body .kp { color: #954121 } /* Keyword.Pseudo */ | ||
157 | +body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ | ||
158 | +body .kt { color: #B00040 } /* Keyword.Type */ | ||
159 | +body .m { color: #666666 } /* Literal.Number */ | ||
160 | +body .s { color: #219161 } /* Literal.String */ | ||
161 | +body .na { color: #7D9029 } /* Name.Attribute */ | ||
162 | +body .nb { color: #954121 } /* Name.Builtin */ | ||
163 | +body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ | ||
164 | +body .no { color: #880000 } /* Name.Constant */ | ||
165 | +body .nd { color: #AA22FF } /* Name.Decorator */ | ||
166 | +body .ni { color: #999999; font-weight: bold } /* Name.Entity */ | ||
167 | +body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ | ||
168 | +body .nf { color: #0000FF } /* Name.Function */ | ||
169 | +body .nl { color: #A0A000 } /* Name.Label */ | ||
170 | +body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ | ||
171 | +body .nt { color: #954121; font-weight: bold } /* Name.Tag */ | ||
172 | +body .nv { color: #19469D } /* Name.Variable */ | ||
173 | +body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ | ||
174 | +body .w { color: #bbbbbb } /* Text.Whitespace */ | ||
175 | +body .mf { color: #666666 } /* Literal.Number.Float */ | ||
176 | +body .mh { color: #666666 } /* Literal.Number.Hex */ | ||
177 | +body .mi { color: #666666 } /* Literal.Number.Integer */ | ||
178 | +body .mo { color: #666666 } /* Literal.Number.Oct */ | ||
179 | +body .sb { color: #219161 } /* Literal.String.Backtick */ | ||
180 | +body .sc { color: #219161 } /* Literal.String.Char */ | ||
181 | +body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ | ||
182 | +body .s2 { color: #219161 } /* Literal.String.Double */ | ||
183 | +body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ | ||
184 | +body .sh { color: #219161 } /* Literal.String.Heredoc */ | ||
185 | +body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ | ||
186 | +body .sx { color: #954121 } /* Literal.String.Other */ | ||
187 | +body .sr { color: #BB6688 } /* Literal.String.Regex */ | ||
188 | +body .s1 { color: #219161 } /* Literal.String.Single */ | ||
189 | +body .ss { color: #19469D } /* Literal.String.Symbol */ | ||
190 | +body .bp { color: #954121 } /* Name.Builtin.Pseudo */ | ||
191 | +body .vc { color: #19469D } /* Name.Variable.Class */ | ||
192 | +body .vg { color: #19469D } /* Name.Variable.Global */ | ||
193 | +body .vi { color: #19469D } /* Name.Variable.Instance */ | ||
194 | +body .il { color: #666666 } /* Literal.Number.Integer.Long */ | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
node_modules/pkginfo/docs/pkginfo.html
0 → 100644
This diff is collapsed. Click to expand it.
1 | +/* | ||
2 | + * all-properties.js: Sample of including all properties from a package.json file | ||
3 | + * | ||
4 | + * (C) 2011, Charlie Robbins | ||
5 | + * | ||
6 | + */ | ||
7 | + | ||
8 | +var util = require('util'), | ||
9 | + pkginfo = require('../lib/pkginfo')(module); | ||
10 | + | ||
11 | +exports.someFunction = function () { | ||
12 | + console.log('some of your custom logic here'); | ||
13 | +}; | ||
14 | + | ||
15 | +console.log('Inspecting module:'); | ||
16 | +console.dir(module.exports); | ||
17 | + | ||
18 | +console.log('\nAll exports exposed:'); | ||
19 | +console.error(Object.keys(module.exports)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * array-argument.js: Sample of including specific properties from a package.json file | ||
3 | + * using Array argument syntax. | ||
4 | + * | ||
5 | + * (C) 2011, Charlie Robbins | ||
6 | + * | ||
7 | + */ | ||
8 | + | ||
9 | +var util = require('util'), | ||
10 | + pkginfo = require('../lib/pkginfo')(module, ['version', 'author']); | ||
11 | + | ||
12 | +exports.someFunction = function () { | ||
13 | + console.log('some of your custom logic here'); | ||
14 | +}; | ||
15 | + | ||
16 | +console.log('Inspecting module:'); | ||
17 | +console.dir(module.exports); | ||
18 | + | ||
19 | +console.log('\nAll exports exposed:'); | ||
20 | +console.error(Object.keys(module.exports)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * multiple-properties.js: Sample of including multiple properties from a package.json file | ||
3 | + * | ||
4 | + * (C) 2011, Charlie Robbins | ||
5 | + * | ||
6 | + */ | ||
7 | + | ||
8 | +var util = require('util'), | ||
9 | + pkginfo = require('../lib/pkginfo')(module, 'version', 'author'); | ||
10 | + | ||
11 | +exports.someFunction = function () { | ||
12 | + console.log('some of your custom logic here'); | ||
13 | +}; | ||
14 | + | ||
15 | +console.log('Inspecting module:'); | ||
16 | +console.dir(module.exports); | ||
17 | + | ||
18 | +console.log('\nAll exports exposed:'); | ||
19 | +console.error(Object.keys(module.exports)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * object-argument.js: Sample of including specific properties from a package.json file | ||
3 | + * using Object argument syntax. | ||
4 | + * | ||
5 | + * (C) 2011, Charlie Robbins | ||
6 | + * | ||
7 | + */ | ||
8 | + | ||
9 | +var util = require('util'), | ||
10 | + pkginfo = require('../lib/pkginfo')(module, { | ||
11 | + include: ['version', 'author'] | ||
12 | + }); | ||
13 | + | ||
14 | +exports.someFunction = function () { | ||
15 | + console.log('some of your custom logic here'); | ||
16 | +}; | ||
17 | + | ||
18 | +console.log('Inspecting module:'); | ||
19 | +console.dir(module.exports); | ||
20 | + | ||
21 | +console.log('\nAll exports exposed:'); | ||
22 | +console.error(Object.keys(module.exports)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
node_modules/pkginfo/examples/package.json
0 → 100644
1 | +{ | ||
2 | + "name": "simple-app", | ||
3 | + "description": "A test fixture for pkginfo", | ||
4 | + "version": "0.1.0", | ||
5 | + "author": "Charlie Robbins <charlie.robbins@gmail.com>", | ||
6 | + "keywords": ["test", "fixture"], | ||
7 | + "main": "./index.js", | ||
8 | + "scripts": { "test": "vows test/*-test.js --spec" }, | ||
9 | + "engines": { "node": ">= 0.4.0" } | ||
10 | +} |
1 | +/* | ||
2 | + * single-property.js: Sample of including a single specific properties from a package.json file | ||
3 | + * | ||
4 | + * (C) 2011, Charlie Robbins | ||
5 | + * | ||
6 | + */ | ||
7 | + | ||
8 | +var util = require('util'), | ||
9 | + pkginfo = require('../lib/pkginfo')(module, 'version'); | ||
10 | + | ||
11 | +exports.someFunction = function () { | ||
12 | + console.log('some of your custom logic here'); | ||
13 | +}; | ||
14 | + | ||
15 | +console.log('Inspecting module:'); | ||
16 | +console.dir(module.exports); | ||
17 | + | ||
18 | +console.log('\nAll exports exposed:'); | ||
19 | +console.error(Object.keys(module.exports)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +{ | ||
2 | + "name": "simple-app-subdir", | ||
3 | + "description": "A test fixture for pkginfo", | ||
4 | + "version": "0.1.0", | ||
5 | + "author": "Charlie Robbins <charlie.robbins@gmail.com>", | ||
6 | + "keywords": ["test", "fixture"], | ||
7 | + "main": "./index.js", | ||
8 | + "scripts": { "test": "vows test/*-test.js --spec" }, | ||
9 | + "engines": { "node": ">= 0.4.0" }, | ||
10 | + "subdironly": "true" | ||
11 | +} |
node_modules/pkginfo/examples/target-dir.js
0 → 100644
1 | +/* | ||
2 | + * multiple-properties.js: Sample of including multiple properties from a package.json file | ||
3 | + * | ||
4 | + * (C) 2011, Charlie Robbins | ||
5 | + * | ||
6 | + */ | ||
7 | + | ||
8 | +var util = require('util'), | ||
9 | + path = require('path'), | ||
10 | + pkginfo = require('../lib/pkginfo')(module, { dir: path.resolve(__dirname, 'subdir' )}); | ||
11 | + | ||
12 | +exports.someFunction = function () { | ||
13 | + console.log('some of your custom logic here'); | ||
14 | +}; | ||
15 | + | ||
16 | +console.log('Inspecting module:'); | ||
17 | +console.dir(module.exports); | ||
18 | + | ||
19 | +console.log('\nAll exports exposed:'); | ||
20 | +console.error(Object.keys(module.exports)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
node_modules/pkginfo/lib/pkginfo.js
0 → 100644
1 | +/* | ||
2 | + * pkginfo.js: Top-level include for the pkginfo module | ||
3 | + * | ||
4 | + * (C) 2011, Charlie Robbins | ||
5 | + * | ||
6 | + */ | ||
7 | + | ||
8 | +var fs = require('fs'), | ||
9 | + path = require('path'); | ||
10 | + | ||
11 | +// | ||
12 | +// ### function pkginfo ([options, 'property', 'property' ..]) | ||
13 | +// #### @pmodule {Module} Parent module to read from. | ||
14 | +// #### @options {Object|Array|string} **Optional** Options used when exposing properties. | ||
15 | +// #### @arguments {string...} **Optional** Specified properties to expose. | ||
16 | +// Exposes properties from the package.json file for the parent module on | ||
17 | +// it's exports. Valid usage: | ||
18 | +// | ||
19 | +// `require('pkginfo')()` | ||
20 | +// | ||
21 | +// `require('pkginfo')('version', 'author');` | ||
22 | +// | ||
23 | +// `require('pkginfo')(['version', 'author']);` | ||
24 | +// | ||
25 | +// `require('pkginfo')({ include: ['version', 'author'] });` | ||
26 | +// | ||
27 | +var pkginfo = module.exports = function (pmodule, options) { | ||
28 | + var args = [].slice.call(arguments, 2).filter(function (arg) { | ||
29 | + return typeof arg === 'string'; | ||
30 | + }); | ||
31 | + | ||
32 | + // | ||
33 | + // **Parse variable arguments** | ||
34 | + // | ||
35 | + if (Array.isArray(options)) { | ||
36 | + // | ||
37 | + // If the options passed in is an Array assume that | ||
38 | + // it is the Array of properties to expose from the | ||
39 | + // on the package.json file on the parent module. | ||
40 | + // | ||
41 | + options = { include: options }; | ||
42 | + } | ||
43 | + else if (typeof options === 'string') { | ||
44 | + // | ||
45 | + // Otherwise if the first argument is a string, then | ||
46 | + // assume that it is the first property to expose from | ||
47 | + // the package.json file on the parent module. | ||
48 | + // | ||
49 | + options = { include: [options] }; | ||
50 | + } | ||
51 | + | ||
52 | + // | ||
53 | + // **Setup default options** | ||
54 | + // | ||
55 | + options = options || {}; | ||
56 | + | ||
57 | + // ensure that includes have been defined | ||
58 | + options.include = options.include || []; | ||
59 | + | ||
60 | + if (args.length > 0) { | ||
61 | + // | ||
62 | + // If additional string arguments have been passed in | ||
63 | + // then add them to the properties to expose on the | ||
64 | + // parent module. | ||
65 | + // | ||
66 | + options.include = options.include.concat(args); | ||
67 | + } | ||
68 | + | ||
69 | + var pkg = pkginfo.read(pmodule, options.dir).package; | ||
70 | + Object.keys(pkg).forEach(function (key) { | ||
71 | + if (options.include.length > 0 && !~options.include.indexOf(key)) { | ||
72 | + return; | ||
73 | + } | ||
74 | + | ||
75 | + if (!pmodule.exports[key]) { | ||
76 | + pmodule.exports[key] = pkg[key]; | ||
77 | + } | ||
78 | + }); | ||
79 | + | ||
80 | + return pkginfo; | ||
81 | +}; | ||
82 | + | ||
83 | +// | ||
84 | +// ### function find (dir) | ||
85 | +// #### @pmodule {Module} Parent module to read from. | ||
86 | +// #### @dir {string} **Optional** Directory to start search from. | ||
87 | +// Searches up the directory tree from `dir` until it finds a directory | ||
88 | +// which contains a `package.json` file. | ||
89 | +// | ||
90 | +pkginfo.find = function (pmodule, dir) { | ||
91 | + if (! dir) { | ||
92 | + dir = path.dirname(pmodule.filename); | ||
93 | + } | ||
94 | + | ||
95 | + var files = fs.readdirSync(dir); | ||
96 | + | ||
97 | + if (~files.indexOf('package.json')) { | ||
98 | + return path.join(dir, 'package.json'); | ||
99 | + } | ||
100 | + | ||
101 | + if (dir === '/') { | ||
102 | + throw new Error('Could not find package.json up from: ' + dir); | ||
103 | + } | ||
104 | + else if (!dir || dir === '.') { | ||
105 | + throw new Error('Cannot find package.json from unspecified directory'); | ||
106 | + } | ||
107 | + | ||
108 | + return pkginfo.find(pmodule, path.dirname(dir)); | ||
109 | +}; | ||
110 | + | ||
111 | +// | ||
112 | +// ### function read (pmodule, dir) | ||
113 | +// #### @pmodule {Module} Parent module to read from. | ||
114 | +// #### @dir {string} **Optional** Directory to start search from. | ||
115 | +// Searches up the directory tree from `dir` until it finds a directory | ||
116 | +// which contains a `package.json` file and returns the package information. | ||
117 | +// | ||
118 | +pkginfo.read = function (pmodule, dir) { | ||
119 | + dir = pkginfo.find(pmodule, dir); | ||
120 | + | ||
121 | + var data = fs.readFileSync(dir).toString(); | ||
122 | + | ||
123 | + return { | ||
124 | + dir: dir, | ||
125 | + package: JSON.parse(data) | ||
126 | + }; | ||
127 | +}; | ||
128 | + | ||
129 | +// | ||
130 | +// Call `pkginfo` on this module and expose version. | ||
131 | +// | ||
132 | +pkginfo(module, { | ||
133 | + dir: __dirname, | ||
134 | + include: ['version'], | ||
135 | + target: pkginfo | ||
136 | +}); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
node_modules/pkginfo/package.json
0 → 100644
1 | +{ | ||
2 | + "name": "pkginfo", | ||
3 | + "version": "0.3.1", | ||
4 | + "license": "MIT", | ||
5 | + "description": "An easy way to expose properties on a module from a package.json", | ||
6 | + "author": "Charlie Robbins <charlie.robbins@gmail.com>", | ||
7 | + "repository": { | ||
8 | + "type": "git", | ||
9 | + "url": "http://github.com/indexzero/node-pkginfo.git" | ||
10 | + }, | ||
11 | + "bugs": { | ||
12 | + "url": "https://github.com/indexzero/node-pkginfo/issues" | ||
13 | + }, | ||
14 | + "keywords": ["info", "tools", "package.json"], | ||
15 | + "devDependencies": { | ||
16 | + "vows": "0.7.x" | ||
17 | + }, | ||
18 | + "main": "./lib/pkginfo.js", | ||
19 | + "scripts": { "test": "vows test/*-test.js --spec" }, | ||
20 | + "engines": { "node": ">= 0.4.0" } | ||
21 | +} |
node_modules/pkginfo/test/pkginfo-test.js
0 → 100644
1 | +/* | ||
2 | + * pkginfo-test.js: Tests for the pkginfo module. | ||
3 | + * | ||
4 | + * (C) 2011, Charlie Robbins | ||
5 | + * | ||
6 | + */ | ||
7 | + | ||
8 | +var assert = require('assert'), | ||
9 | + exec = require('child_process').exec, | ||
10 | + fs = require('fs'), | ||
11 | + path = require('path'), | ||
12 | + vows = require('vows'), | ||
13 | + pkginfo = require('../lib/pkginfo'); | ||
14 | + | ||
15 | +function assertProperties (source, target) { | ||
16 | + assert.lengthOf(source, target.length + 1); | ||
17 | + target.forEach(function (prop) { | ||
18 | + assert.isTrue(!!~source.indexOf(prop)); | ||
19 | + }); | ||
20 | +} | ||
21 | + | ||
22 | +function compareWithExample(targetPath) { | ||
23 | + var examplePaths = ['package.json']; | ||
24 | + | ||
25 | + if (targetPath) { | ||
26 | + examplePaths.unshift(targetPath); | ||
27 | + } | ||
28 | + | ||
29 | + return function(exposed) { | ||
30 | + var pkg = fs.readFileSync(path.join.apply(null, [__dirname, '..', 'examples'].concat(examplePaths))).toString(), | ||
31 | + keys = Object.keys(JSON.parse(pkg)); | ||
32 | + | ||
33 | + assertProperties(exposed, keys); | ||
34 | + }; | ||
35 | +} | ||
36 | + | ||
37 | +function testExposes (options) { | ||
38 | + return { | ||
39 | + topic: function () { | ||
40 | + exec('node ' + path.join(__dirname, '..', 'examples', options.script), this.callback); | ||
41 | + }, | ||
42 | + "should expose that property correctly": function (err, stdout, stderr) { | ||
43 | + assert.isNull(err); | ||
44 | + | ||
45 | + var exposed = stderr.match(/'(\w+)'/ig).map(function (p) { | ||
46 | + return p.substring(1, p.length - 1); | ||
47 | + }); | ||
48 | + | ||
49 | + return !options.assert | ||
50 | + ? assertProperties(exposed, options.properties) | ||
51 | + : options.assert(exposed); | ||
52 | + } | ||
53 | + } | ||
54 | +} | ||
55 | + | ||
56 | +vows.describe('pkginfo').addBatch({ | ||
57 | + "When using the pkginfo module": { | ||
58 | + "and passed a single `string` argument": testExposes({ | ||
59 | + script: 'single-property.js', | ||
60 | + properties: ['version'] | ||
61 | + }), | ||
62 | + "and passed multiple `string` arguments": testExposes({ | ||
63 | + script: 'multiple-properties.js', | ||
64 | + properties: ['version', 'author'] | ||
65 | + }), | ||
66 | + "and passed an `object` argument": testExposes({ | ||
67 | + script: 'object-argument.js', | ||
68 | + properties: ['version', 'author'] | ||
69 | + }), | ||
70 | + "and passed an `array` argument": testExposes({ | ||
71 | + script: 'array-argument.js', | ||
72 | + properties: ['version', 'author'] | ||
73 | + }), | ||
74 | + "and read from a specified directory": testExposes({ | ||
75 | + script: 'target-dir.js', | ||
76 | + assert: compareWithExample('subdir') | ||
77 | + }), | ||
78 | + "and passed no arguments": testExposes({ | ||
79 | + script: 'all-properties.js', | ||
80 | + assert: compareWithExample() | ||
81 | + }) | ||
82 | + } | ||
83 | +}).export(module); |
... | @@ -14,6 +14,7 @@ | ... | @@ -14,6 +14,7 @@ |
14 | "express": "^4.17.1", | 14 | "express": "^4.17.1", |
15 | "express-flash": "^0.0.2", | 15 | "express-flash": "^0.0.2", |
16 | "fs": "^0.0.1-security", | 16 | "fs": "^0.0.1-security", |
17 | + "passport-kakao": "^1.0.1", | ||
17 | "passport-naver": "^1.0.6", | 18 | "passport-naver": "^1.0.6", |
18 | "path": "^0.12.7", | 19 | "path": "^0.12.7", |
19 | "request": "^2.88.2", | 20 | "request": "^2.88.2", |
... | @@ -1750,6 +1751,28 @@ | ... | @@ -1750,6 +1751,28 @@ |
1750 | "node": ">= 0.4.0" | 1751 | "node": ">= 0.4.0" |
1751 | } | 1752 | } |
1752 | }, | 1753 | }, |
1754 | + "node_modules/passport-kakao": { | ||
1755 | + "version": "1.0.1", | ||
1756 | + "resolved": "https://registry.npmjs.org/passport-kakao/-/passport-kakao-1.0.1.tgz", | ||
1757 | + "integrity": "sha512-uItaYRVrTHL6iGPMnMZvPa/O1GrAdh/V6EMjOHcFlQcVroZ9wgG7BZ5PonMNJCxfHQ3L2QVNRnzhKWUzSsumbw==", | ||
1758 | + "dependencies": { | ||
1759 | + "passport-oauth2": "~1.1.2", | ||
1760 | + "pkginfo": "~0.3.0" | ||
1761 | + } | ||
1762 | + }, | ||
1763 | + "node_modules/passport-kakao/node_modules/passport-oauth2": { | ||
1764 | + "version": "1.1.2", | ||
1765 | + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.1.2.tgz", | ||
1766 | + "integrity": "sha1-vXFjsbYJA3GGjcTvb58uHkzEuUg=", | ||
1767 | + "dependencies": { | ||
1768 | + "oauth": "0.9.x", | ||
1769 | + "passport-strategy": "1.x.x", | ||
1770 | + "uid2": "0.0.x" | ||
1771 | + }, | ||
1772 | + "engines": { | ||
1773 | + "node": ">= 0.4.0" | ||
1774 | + } | ||
1775 | + }, | ||
1753 | "node_modules/passport-local": { | 1776 | "node_modules/passport-local": { |
1754 | "version": "1.0.0", | 1777 | "version": "1.0.0", |
1755 | "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", | 1778 | "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", |
... | @@ -1864,6 +1887,14 @@ | ... | @@ -1864,6 +1887,14 @@ |
1864 | "url": "https://github.com/sponsors/jonschlinkert" | 1887 | "url": "https://github.com/sponsors/jonschlinkert" |
1865 | } | 1888 | } |
1866 | }, | 1889 | }, |
1890 | + "node_modules/pkginfo": { | ||
1891 | + "version": "0.3.1", | ||
1892 | + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", | ||
1893 | + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=", | ||
1894 | + "engines": { | ||
1895 | + "node": ">= 0.4.0" | ||
1896 | + } | ||
1897 | + }, | ||
1867 | "node_modules/prepend-http": { | 1898 | "node_modules/prepend-http": { |
1868 | "version": "2.0.0", | 1899 | "version": "2.0.0", |
1869 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", | 1900 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", |
... | @@ -4017,6 +4048,27 @@ | ... | @@ -4017,6 +4048,27 @@ |
4017 | "pause": "0.0.1" | 4048 | "pause": "0.0.1" |
4018 | } | 4049 | } |
4019 | }, | 4050 | }, |
4051 | + "passport-kakao": { | ||
4052 | + "version": "1.0.1", | ||
4053 | + "resolved": "https://registry.npmjs.org/passport-kakao/-/passport-kakao-1.0.1.tgz", | ||
4054 | + "integrity": "sha512-uItaYRVrTHL6iGPMnMZvPa/O1GrAdh/V6EMjOHcFlQcVroZ9wgG7BZ5PonMNJCxfHQ3L2QVNRnzhKWUzSsumbw==", | ||
4055 | + "requires": { | ||
4056 | + "passport-oauth2": "~1.1.2", | ||
4057 | + "pkginfo": "~0.3.0" | ||
4058 | + }, | ||
4059 | + "dependencies": { | ||
4060 | + "passport-oauth2": { | ||
4061 | + "version": "1.1.2", | ||
4062 | + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.1.2.tgz", | ||
4063 | + "integrity": "sha1-vXFjsbYJA3GGjcTvb58uHkzEuUg=", | ||
4064 | + "requires": { | ||
4065 | + "oauth": "0.9.x", | ||
4066 | + "passport-strategy": "1.x.x", | ||
4067 | + "uid2": "0.0.x" | ||
4068 | + } | ||
4069 | + } | ||
4070 | + } | ||
4071 | + }, | ||
4020 | "passport-local": { | 4072 | "passport-local": { |
4021 | "version": "1.0.0", | 4073 | "version": "1.0.0", |
4022 | "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", | 4074 | "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", |
... | @@ -4102,6 +4154,11 @@ | ... | @@ -4102,6 +4154,11 @@ |
4102 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", | 4154 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", |
4103 | "dev": true | 4155 | "dev": true |
4104 | }, | 4156 | }, |
4157 | + "pkginfo": { | ||
4158 | + "version": "0.3.1", | ||
4159 | + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", | ||
4160 | + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" | ||
4161 | + }, | ||
4105 | "prepend-http": { | 4162 | "prepend-http": { |
4106 | "version": "2.0.0", | 4163 | "version": "2.0.0", |
4107 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", | 4164 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", | ... | ... |
... | @@ -19,6 +19,7 @@ | ... | @@ -19,6 +19,7 @@ |
19 | "express": "^4.17.1", | 19 | "express": "^4.17.1", |
20 | "express-flash": "^0.0.2", | 20 | "express-flash": "^0.0.2", |
21 | "fs": "^0.0.1-security", | 21 | "fs": "^0.0.1-security", |
22 | + "passport-kakao": "^1.0.1", | ||
22 | "passport-naver": "^1.0.6", | 23 | "passport-naver": "^1.0.6", |
23 | "path": "^0.12.7", | 24 | "path": "^0.12.7", |
24 | "request": "^2.88.2", | 25 | "request": "^2.88.2", | ... | ... |
1 | -{"cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"},"flash":{"error":["Missing username or password."]},"__lastAccess":1638110555478} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +{"cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"},"flash":{"error":["Missing username or password."]},"__lastAccess":1638446277022} | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or login to post a comment