도서관에 도서 요청

도서관에 책을 등록하는 프로그램 입니다. 기존에 JAVA로 만들어진 모듈을 nodejs로 변경 하였습니다.
JAVA 소스의 경우 selenium을 설치하고 설정해야하는 부분이 많았는데 puppeteer를 이용하면 간단하게 최소한의 설정으로 처리가 가능하다.

프로그램 설계

부천 시립 도서관에서 한달에 요청 할 수 있는 도서는 다음과 같다.

  • 상동, 심곡, 꿈빛, 책마루, 송내도서관 : 1인당 월 5권
  • 원미, 북부, 한울빛, 꿈여울도서관 : 1인당 월 20권

이에 도서 목록을 다음과 같이 TXT 파일로 작성하연 자동으로 등록 하도록 한다.

도서목록 파일 내용 샘플

도서관코드|도서명
AA|즐거운하루
AB|자동책등록프로그램

도서관 코드

2019년 부터 상동, 심곡, 꿈빛, 책마루, 송내, 동화도서관: 1인당 월 5권 으로 변경 되었습니다.

아래 내용은 2017년 기준 내용입니다.

도서관코드 도서관명 비고
AA 상동 월5권
AB 원미 월20권
AC 삼곡 월5권
AD 북부 월20권
AE 꿈빛 월5권
AF 책마루 월5권
AG 한울빛 월20권
AH 꿈여울 월20권
AI 송내 월5권
AK 도당 월20권

프로세스 순서도

프로세스 순서도

Notice

  • nodejs 필요
  • _env 를 .env 로 파일명 변경
  • .env 에 ID/PW 작성

실행 방법

# 모듈 설치
npm install

# 실행
npm run start

License

희망 도서 자동 등록 프로그램은 open source 프로그램으로 MIT 라이선스를 따릅니다.

This Request book apply is free and open source software, distributed under the MIT License. So feel free to use this program on your project without linking back to me or including a disclaimer.

Posted by lahuman

댓글을 달아 주세요

Reactjs 초기 프로젝트 구성하기

Reactjs 초기 프로젝트를 구성하려는 방법 중 가장 쉽고 널리 알려진 것은 Create React App를 이용하는 방법이다. 아래와 같이 실행하면 바로 프로젝트 구성이 완료된다.

npx create-react-app my-app
cd my-app
npm start

아쉬운 점은 무엇이 설치 되었는지 내가 알지 못하고, 또한 컴파일에 오랜 시간이 걸린다.

npm run eject를 이용해서 묶음을 풀어 보면 너무 많은 것들이 설치 되어 있다.

그래서 방법을 찾아 보던 중 @babel/preset-env와 plugins이라는 유튜브를 보고 한땀씩 진행을 해보았다.

우선 나에게 필요한 기본 모듈은 다음과 같다.

기본 모듈

  • react
  • react-dom
  • react
  • react-router-dom
  • dotenv
  • axois

이들을 모두 설치하고 기본 테스트까지 된 프로젝트를 만들어 보았다.

진행하면서 수정사항이 바로 바로 반영되는 React Hot Loader도 알게되어 추가 하였다.

또한 컴파일을 위해 웹팩 설정을 하고 한땀 한땀 진행해보았다.

어려운듯 쉬운듯 꽤 많은 시간이 소비 하고야 내가 원하는 결과를 확인 할 수 있었다.

ReactJS-Start

많이 삽질하면서 많이 배운 시간이었다.

참고자료

Posted by lahuman

댓글을 달아 주세요

vim upgrade or 업그레이드 내역 확인 하기!

Vim과 Neovim 편집기에서 OS 명령어 실행 취약점 발견 2019.06.13

  • 보안 연구원 Armin Razmjou는 최근 리눅스에서 가장 인기 있는 커맨드라인 텍스트 편집 유틸리티인 Vim과 Neovim에서 심각도 높은 임의 OS 명령 실행 취약점(CVE-2019-12735)을 발견
    • Vim 편집기 : 사용자들이 리눅스에서 텍스트, 스크립트, 문서를 포함한 파일을 생성하고, 열람하거나 수정할 수 있는 프로그램
      • Neovim 편집기 : 플러그인, GUI 등이 개선된 Vim 확장 버전 프로그램
  • 이 취약점은 “modlines”를 처리하는 과정에서 발견됨
    + modelines : 문서의 시작과 마지막 라인 근처에 파일의 제작자가 언급한 커스텀 설정 세트를 자동으로 찾아 적용하는 기능으로 기본으로
                          활성화되어 있음
  • 비록 보안상의 이유로 modelines의 서브셋만을 허용하고 샌드박스 보호를 사용할지라도 “:source!” 명령어를 사용하면 샌드박스를
    우회할 수 있음

  • 따라서, Vim이나 Neovim을 사용해 특별히 제작된 파일을 열람하는 것만으로도 공격자가 피해자의 리눅스 시스템에서 명령을 실행하고
    제어권을 탈취할 수 있음

  • Vim(8.1.1365)과 Neovim(v0.3.6)은 해당 취약점 문제 해결을 위해 최근 업데이트를 발표

  • 해결 방안

    • modelines 기능 비활성화
    • modelines의 수식을 비활성화 하기 위한 “modelineexpr” 비활성화
    • Vim modelines의 대한인 “securemodelines plugin” 사용

시사점

  • 리눅스 및 Vim과 Neovim 에디터를 최신 버전으로 업데이트하고, 주기적인 권한 탈취 여부 확인

vim 확인 하기

vim upgrade 하기

sudo apt-get upgrade vim 명령어를 이용해서 업그레이드를 할 수 있다.

만약 업그레이드를 할 내용이 없으면 다음과 같은 결과가 확이 된다.

$> sudo apt-get upgrade vim
Reading package lists... Done
Building dependency tree
Reading state information... Done
vim is already the newest version (2:8.0.1453-1ubuntu1.1).
Calculating upgrade... Done
The following package was automatically installed and is no longer required:
  linux-aws-headers-4.15.0-1035
Use 'sudo apt autoremove' to remove it.
The following packages have been kept back:
  linux-aws linux-headers-aws linux-image-aws
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

vim 최신 버젼으로 강제 업데이트 하기

PPA를 이용해서 최신 버젼으로 업데이트를 한다.

$> sudo add-apt-repository ppa:jonathonf/vim
$> sudo apt update
$> sudo apt install vim

vim upgrade 내역 확인 하기

changelog를 확인하면 업데이트 기록이 확인 된다. 다음과 같인 로그가 있다면, CVE-2019-12735.patch에 대한 패치가 되어 있는 것이다.

$> apt changelog vim
vim (2:8.0.1453-1ubuntu1.1) bionic-security; urgency=medium

  * SECURITY UPDATE: Arbitrary code execution
    - debian/patches/CVE-2019-12735.patch: disallow
      sourcing a file in the sandbox in src/getchar.c
    - CVE-2019-12735

 -- Leonidas S. Barbosa <leo.barbosa@canonical.com>  Thu, 06 Jun 2019 14:31:41 -0300

대부분 서비스를 확인하니 이미 패치가 되어 있었다.

참고자료

Posted by lahuman

댓글을 달아 주세요

Maven을 이용한 Springboot 프로젝트 repackage 하기

다른 분이 작성한 Springboot 프로젝트를 패키징하게 되었다.

해당 프로젝트는 maven으로 되어 있었기에 큰 문제가 없을꺼라 생각했다.

내 업무 환경은 JDK 12가 설치되어 있었는데, spring-repackage를 하면 다음과 같은 오류가 발생하였다.

ERROR] Failed to execute goal org.apache.maven.plugins:maven-jar-plugin:2.6:jar (default-jar) on project my-test-utils: Execution default-jar of goal org.apache.maven.plugins:maven-jar-plugin:2.6:jar failed: An API incompatibility was encountered while executing org.apache.maven.plugins:maven-jar-plugin:2.6:jar: java.lang.ExceptionInInitializerError: null
[ERROR] -----------------------------------------------------
[ERROR] realm =    plugin>org.apache.maven.plugins:maven-jar-plugin:2.6

에러 발생의 원인은 maven-plugin 버전 문제로, 다음과 같이 pom.xml에 추가 하면 된다.

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.1.0</version>
        </plugin>
    </plugins>
</build>

추가로 다음과 같은 오류가 발생하면,

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.5.21.RELEASE:repackage (default-cli) on project lahuman: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:1.5.21.RELEASE:repackage failed: Source file must be provided -> [Help 1]

Maven 배포시 Local Jar 파일과 함께 하기!내용과 같이 spring:repackage에 -U 옵션을 추가하면 해결 된다.

오랜만에 JAVA 보는듯 하다. 요즘은 개인 프로젝트도 그냥 NODE로 개발 하게 된다.

참고자료

Posted by lahuman

댓글을 달아 주세요

express에서 File Upload 구현 하기

업로드는 복잡하게 구현 하지 않고 모듈을 사용하면 쉽게 할 수 있다.

express-fileupload를 이용하면 된다.

# express 의 app.js 에서 다음과 같이 사용 
const fileUpload = require('express-fileupload');
const cors = require('cors');
const fs = require('fs');

app.use(cors());
app.use(fileUpload());

app.post('/upload', (req, res, next) => {
  let uploadFile = req.files.file
  const fileName = req.files.file.name
  uploadFile.mv(
    `${__dirname}/public/files/${fileName}`,
    function (err) {
      if (err) {
        return res.status(500).send(err);
      }

      res.json(JSON.parse(fs.readFileSync(`${__dirname}/public/files/${fileName}`, 'utf8')));
    }
  );
})

그게 어렵지 않게 한다.

참고자료

Posted by lahuman

댓글을 달아 주세요

google docs Sheets 연동 하기

이번에 진행되는 프로젝트에서 데이터를 Google Docs의 Sheets에 넣어 두고 해당 데이터를 활용하여 대시보드를 구현하게 되었다.

Google Sheets API 소개에도 잘 나와 있듯이, API를 활용하여 쉽게 이용할 수 있다.

Node.js Quickstart에서 제공되는 소스는 아래와 같다.

const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');

// If modifying these scopes, delete token.json.
const SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly'];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = 'token.json';

// Load client secrets from a local file.
fs.readFile('credentials.json', (err, content) => {
  if (err) return console.log('Error loading client secret file:', err);
  // Authorize a client with credentials, then call the Google Sheets API.
  authorize(JSON.parse(content), listMajors);
});

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(credentials, callback) {
  const {client_secret, client_id, redirect_uris} = credentials.installed;
  const oAuth2Client = new google.auth.OAuth2(
      client_id, client_secret, redirect_uris[0]);

  // Check if we have previously stored a token.
  fs.readFile(TOKEN_PATH, (err, token) => {
    if (err) return getNewToken(oAuth2Client, callback);
    oAuth2Client.setCredentials(JSON.parse(token));
    callback(oAuth2Client);
  });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
function getNewToken(oAuth2Client, callback) {
  const authUrl = oAuth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: SCOPES,
  });
  console.log('Authorize this app by visiting this url:', authUrl);
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  rl.question('Enter the code from that page here: ', (code) => {
    rl.close();
    oAuth2Client.getToken(code, (err, token) => {
      if (err) return console.error('Error while trying to retrieve access token', err);
      oAuth2Client.setCredentials(token);
      // Store the token to disk for later program executions
      fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
        if (err) return console.error(err);
        console.log('Token stored to', TOKEN_PATH);
      });
      callback(oAuth2Client);
    });
  });
}

/**
 * Prints the names and majors of students in a sample spreadsheet:
 * @see https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
 * @param {google.auth.OAuth2} auth The authenticated Google OAuth client.
 */
function listMajors(auth) {
  const sheets = google.sheets({version: 'v4', auth});
  sheets.spreadsheets.values.get({
    spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
    range: 'Class Data!A2:E',
  }, (err, res) => {
    if (err) return console.log('The API returned an error: ' + err);
    const rows = res.data.values;
    if (rows.length) {
      console.log('Name, Major:');
      // Print columns A and E, which correspond to indices 0 and 4.
      rows.map((row) => {
        console.log(`${row[0]}, ${row[4]}`);
      });
    } else {
      console.log('No data found.');
    }
  });
}

참 좋은 세상이다!

참고자료

Posted by lahuman

댓글을 달아 주세요

NodeJs에서 Parse Error: HPE_HEADER_OVERFLOW 발생

x-ray(node moudle)를 이용해서 크롤링을 개발하고 있던 중, 다음과 같은 오류를 만나게 되었다.

(node:63533) UnhandledPromiseRejectionWarning: Error: Parse Error
    at Socket.socketOnData (_http_client.js:442:20)
    at Socket.emit (events.js:189:13)
    at addChunk (_stream_readable.js:284:12)
    at readableAddChunk (_stream_readable.js:265:11)
    at Socket.Readable.push (_stream_readable.js:220:10)
    at TCP.onStreamRead (internal/stream_base_commons.js:94:17)
     bytesParsed: 6545,
  code: 'HPE_HEADER_OVERFLOW',

이 오류는 3개의 사이트중 1개의 사이트에서만 발생하였다.

원인을 파악하기 위해 검색을 하다 다음과 같은 내용을 확인하였다.

Node.js의 http 80KB의 Header 크기 제한을 가지고 있고 만약 큰 Header 크기가 필요 하다면, 명령을 실행시 특정 argument를 추가 해야 한다.

해결책은 다음과 같다!

실행하는 node 명령와 함께 --max-http-header-size=크기 argument를 추가 해라

예제)

$> node --max-http-header-size=81000 app.js

에러가 안날때 까지 최대 http header 크기를 키우면 된다.

근데... 이건 에러나는 사이트가 문제 아닌가? 80KB를 넘는 헤더를 왜 넘기지??

참고자료

Posted by lahuman

댓글을 달아 주세요

express에서 stream을 이용하여 파일 다운로드 하기

파일다운로드를 하기위해서는 스트림을 이용해야 한다.

const mime = require('mime-types');

// set header for download
let mimeType = mime.lookup('news_20190501.pdf');
res.setHeader('Content-disposition', 'attachment; filename=' + 'news_20190501.pdf');
res.setHeader('Content-type', mimeType);
fs.createReadStream(__basedir + '/public/files/download/pdf/news_20190501.pdf').pipe(res);

다음과 같이 하면 파일을 스트림을 통해서 다운로드할수 있다.

같이 일하는 분이 알려주심!

자바나 노드나 많이 다르지는 않다!

Posted by lahuman

댓글을 달아 주세요

nodejs package.json의 모듈 업데이트 하기!

npm-check-updates을 이용하여 package.json에 등록된 모듈들을 의존성에 알맞게 최신 버젼으로 업데이트 할 수 있다.

설치 후 실행은 다음과 같다.

# global로 npm-check-updates 설치
$> npm i -g npm-check-updates
# 프로젝트(package.json과 동일한) 디렉토리에서 다음 명령어 실행
$> ncu -u
Upgrading /Users/admin/myProject/package.json
[====================] 17/17 100%

 app-root-path     ^2.1.0  →   ^2.2.1
 cookie-parser     ~1.4.3  →   ~1.4.4
 debug             ~2.6.9  →   ~4.1.1
 dotenv            ^7.0.0  →   ^8.0.0
 express          ~4.16.0  →  ~4.16.4
 express-session  ^1.15.6  →  ^1.16.1
 helmet           ^3.16.0  →  ^3.17.0
 http-errors       ~1.6.2  →   ~1.7.2
 morgan            ~1.9.0  →   ~1.9.1
 puppeteer        ^1.13.0  →  ^1.15.0

Run npm install to install new versions.

# 업데이트된 결과를 설치
$> npm install

자주는 아니더라도, 가끔씩은 모듈을 업데이트 하자!

참고자료

Posted by lahuman

댓글을 달아 주세요

nodejs port forwarding 처리

https를 설정하고 나니, 기존 80 포트로 요청이 있을 경우, 443으로 redirect 하는 방법을 찾아보았다.

구글을 확인해보니, 다음과 같이 쉽게 처리 할 수 있었다.

// Redirect from http port 80 to https
var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
    res.end();
}).listen(80);

구글과 함께면 뭐든 쉽다.

참조 링크

Posted by lahuman

댓글을 달아 주세요