mongoDB의 CSFLE라고 불리는 필드암호화는 mongoDB 4.2이상에서 지원된다.

(단, mongoDB enterprise에서만 지원된다)

 

스텝별로 살펴보면 다음과 같다.

 

1. KMS 서비스를 통해 key 생성. (아래는 AWS KMS이용 예제이지만,  azure의 keyVault나 Google Cloud KMS도 가능)

 

AWS Management Console에 로그인하여 KMS 서비스로 이동합니다.
새로운 키 생성을 선택하고, 키 유형으로 "대칭"을 선택합니다.
키에 이름을 부여하고, 필요한 권한을 설정합니다.
IAM 정책 설정:

키 사용 권한을 가진 IAM 사용자 또는 역할을 생성합니다.
생성된 KMS 키에 대한 액세스 권한을 해당 IAM 사용자 또는 역할에 부여합니다.

 

2. MongoDB 설정에 ClientEncryptions  설정.

@Bean
public MongoClient mongoClient() {
    Map<String, Object> awsKmsProvider = Map.of(
        "accessKeyId", "<AWS_ACCESS_KEY_ID>",
        "secretAccessKey", "<AWS_SECRET_ACCESS_KEY>"
    );

    Map<String, Map<String, Object>> kmsProviders = Map.of("aws", awsKmsProvider);

    AutoEncryptionSettings autoEncryptionSettings = AutoEncryptionSettings.builder()
            .keyVaultNamespace("admin.dataKeys")
            .kmsProviders(kmsProviders)
            .build();

    MongoClientSettings settings = MongoClientSettings.builder()
            .applyConnectionString(new ConnectionString(uri))
            .autoEncryptionSettings(autoEncryptionSettings)
            .build();
    return MongoClients.create(settings);
}

@Bean
public MongoTemplate mongoTemplate() throws Exception {
    return new MongoTemplate(mongoClient(), dbName);
}

 

3. entity class의 필드에 @Encrypted 적용 

 

@Document
public class User {
    @Encrypted
    private String sensitiveData;
    
    private String generalData;
}
Posted by yongary
,

centos7 time 설정

Linux 2024. 4. 15. 17:20

AWS ec2 에서 최근에는 ntp보다 chrony를 많이 사용한다.

 

1. sudo vi /etc/chrony.conf 에서
    server 169.254.169.123 prefer iburst
를 넣는다. 1줄만 있어도 된다.

 

2. sudo systemctl restart chronyd

 

 

3. chronyc sources -v   

  -> 소스서버가 제대로 반영되었는지 확인 (check)

 

4. date 로 시간확인.

 

 

혹시 시간이 다르면 수정 방법.

$sudo timedatectl set-ntp false

$sudo timedatectl set-time "2025-08-19 15:44:00"  (맞는시간으로 설정)

 

$date 로 확인해보고 맞으면

그 후에 다시 ntp살리기.
$sudo timedatectl set-ntp true

$sudo systemctl restart chronyd 

Posted by yongary
,

 

단, https에서만 동작한다.

 

async function copyImageToClipboard(imageUrl) {
    try {
        const response = await fetch(imageUrl);
        const blob = await response.blob();
        await navigator.clipboard.write([
            new ClipboardItem({
                [blob.type]: blob
            })
        ]);
        console.log('Image copied to clipboard');
    } catch (err) {
        console.error('Failed to copy image: ', err);
    }
}

// 이미지 URL과 버튼 클릭 이벤트 핸들러
document.getElementById('copyImageButton').addEventListener('click', function() {
    const imageUrl = 'path/to/your/image.png';
    copyImageToClipboard(imageUrl);
});
Posted by yongary
,

 

로드밸런서 설정시

HTTPS:443 설정에서 아래처럼 하면 웹서버로는 http가 전달되며, 이를 SSL Termination 이라고 부름.

  • 이 설정에서, 트래픽의 "Default actions"을 웹 서버로 트래픽을 HTTP로 전달하도록 구성합니다. 여기서 SSL 종료가 발생하며, ALB가 SSL/TLS 암호화를 해제하고, 결과적으로 내부 서버에는 암호화되지 않은 HTTP 트래픽으로 데이터를 전송합니다. 이는 내부 네트워크의 보안을 기반으로, 성능 최적화와 구성의 단순화를 도모할 수 있습니다.
  • 대상그룹으로 전달해도 동일한 효과가 발생할 것으로 예상됩니다.

 

참고 - NGINX로 전달한 블로그 : https://medium.com/@vdongbin/aws-elb%EC%99%80-nginx%EB%A1%9C-https-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-736b8c5ee76  

 

Posted by yongary
,

CentOs7 에 폰트 설치

Linux 2024. 4. 12. 17:42

1.  폰트 위치는 /usr/share/fonts/arial 

이며, msttcore 폴더 밑에 ms 기본 폰트들이 있는지 확인가능.

 

 

2. 없을시 설치 방법.
  a.  $wget https://www.itzgeek.com/msttcore-fonts-2.0-3.noarch.rpm 
  b.  sudo rpm -Uvh msttcore-fonts-2.0-3.noarch.rpm

  c. 

sudo fc-cache -f -v

 

Posted by yongary
,

 

1. Apps Script 컨솔 왼쪽 메뉴에서 "서비스 +" 를 눌러 Drive API 를 추가한다.

 

2. 코드를 아래와 같이 작성하고

3. 배포 -> 새 배포 를 한 후

4. 실행을 누른다.

function convertDocxToPdf() {
  var folderId = 'myFolderID-folder의 URL 뒤쪽 끝부분임.'; // 변환할 파일이 들어 있는 폴더 ID
  var folder = DriveApp.getFolderById(folderId);
  var files = folder.getFilesByType(MimeType.MICROSOFT_WORD);

  while (files.hasNext()) {
    var file = files.next();
    Logger.log('File name:' + file.getName());

    //1. Microsoft Word 파일을 Google Docs로 변환
    var resource = {
      title: file.getName(),
      mimeType: MimeType.GOOGLE_DOCS,
      parents: [{id: folderId}]
    };

    var convertedDocFile = Drive.Files.copy(resource, file.getId());

    //2. Google Docs 형식으로 문서를 연 후 PDF로 변환
    var doc = DocumentApp.openById(convertedDocFile.getId());
    var blob = doc.getBlob().getAs('application/pdf');

    // 특정 폴더에 PDF 파일 저장
    var folder = DriveApp.getFolderById(folderId);
    var pdfFile = folder.createFile(blob.setName(convertedDocFile.getName().replace(/\.[^/.]+$/, "") + ".pdf"));

    // 생성된 PDF 파일의 URL 반환
    return pdfFile.getUrl();
  }
}

 

 

원격호출이 가능한 appScript만들기 => doGet(e)과 filename 파라미터를 추가.

 

function convertDoc2PdfByFilename(filename) {
  var folderId = 'myFOlderID'; // 변환할 파일이 들어 있는 폴더 ID
  var folder = DriveApp.getFolderById(folderId);
  // var files = folder.getFilesByType(MimeType.MICROSOFT_WORD);
  var files = folder.getFilesByName(filename);

  while (files.hasNext()) {
    var file = files.next();
    Logger.log('File name:' + file.getName());

    //1. Microsoft Word 파일을 Google Docs로 변환
    var resource = {
      title: file.getName(),
      mimeType: MimeType.GOOGLE_DOCS,
      parents: [{id: folderId}]
    };

    var convertedDocFile = Drive.Files.copy(resource, file.getId());

    //2. Google Docs 형식으로 문서를 연 후 PDF로 변환
    var doc = DocumentApp.openById(convertedDocFile.getId());
    var blob = doc.getBlob().getAs('application/pdf');

    // 특정 폴더에 PDF 파일 저장
    var folder = DriveApp.getFolderById(folderId);
    var pdfFile = folder.createFile(blob.setName(convertedDocFile.getName().replace(/\.[^/.]+$/, "") + ".pdf"));

    // 생성된 PDF 파일의 URL 반환
    return pdfFile.getUrl();
  }
}

function doGet(e) {
  var filename = e.parameter.filename;
  if (!filename) {
    return ContentService.createTextOutput("Filename parameter missing")
      .setMimeType(ContentService.MimeType.TEXT);
  }

  // 파일 이름을 사용하여 DOCX를 PDF로 변환하고, 생성된 PDF의 URL을 반환
  var pdfUrl = convertDoc2PdfByFilename(filename);
  if (pdfUrl) {
    return ContentService.createTextOutput("PDF 생성됨: " + pdfUrl)
      .setMimeType(ContentService.MimeType.TEXT);
  } else {
    return ContentService.createTextOutput("해당 이름의 파일을 찾을 수 없습니다.")
      .setMimeType(ContentService.MimeType.TEXT);
  }
}
Posted by yongary
,

springboot에서 pdf로 변환하다가 어려움을 겪는다면, 시도해 볼만한 방법 중하나로
구글드라이브와 구글의 appScript를 이용하는 방법이다.

 

Spring Boot 애플리케이션에서 Google 계정에 로그인하여 Google Apps Script를 실행하고, 결과로 생성된 PDF를 가져오는 것은 가능합니다. 이 과정은 크게 세 부분으로 나눌 수 있습니다: Google 계정 인증, Google Apps Script 실행, 생성된 PDF 파일 가져오기. 이 과정은 Google Cloud Platform(GCP)의 여러 서비스와 API를 사용하며, OAuth 2.0을 통한 인증이 필요합니다.

1. Google 계정 인증 (OAuth 2.0 사용)

  1. Google Cloud Console에서 새 프로젝트를 생성합니다.
  2. API 및 서비스 대시보드로 이동하여 OAuth 동의 화면을 구성합니다.
  3. 사용자 인증 정보를 클릭하여 새 OAuth 클라이언트 ID를 생성합니다. 애플리케이션 유형으로 웹 애플리케이션을 선택합니다.
  4. 승인된 리디렉션 URI로 애플리케이션의 리디렉션 엔드포인트를 추가합니다. 예를 들어, http://localhost:8080/oauth2/callback과 같습니다.
  5. 클라이언트 ID와 클라이언트 비밀을 안전하게 저장합니다.

2. Google Apps Script 실행

  1. Google Apps Script를 사용하여 PDF를 생성하고 Google Drive에 저장하는 스크립트를 작성합니다.
  2. Apps Script 프로젝트에서 공유 및 배포 > 배포를 위한 앱 만들기 > API 실행 가능을 활성화하고, 생성된 스크립트 ID를 저장합니다.

3. Spring Boot에서 Google API 사용

  1. Spring Boot 프로젝트에 google-api-client, google-oauth-client, google-api-services-script 라이브러리를 의존성에 추가합니다.
implementation 'com.google.api-client:google-api-client:1.30.9'
implementation 'com.google.oauth-client:google-oauth-client-jetty:1.30.6'
implementation 'com.google.apis:google-api-services-script:v1-rev20200827-1.30.10'
gradleCopy code
implementation 'com.google.api-client:google-api-client:1.30.9' implementation 'com.google.oauth-client:google-oauth-client-jetty:1.30.6' implementation 'com.google.apis:google-api-services-script:v1-rev20200827-1.30.10'
  1. 사용자를 Google로 리디렉션하여 인증하고, Google로부터 리디렉션된 요청을 처리하는 컨트롤러를 구현합니다. 이 과정에서 GoogleAuthorizationCodeFlow를 사용하여 액세스 토큰을 얻습니다.
  2. 얻은 액세스 토큰을 사용하여 Apps Script API를 호출하고, 스크립트를 실행하여 PDF를 생성합니다.

4. 생성된 PDF 가져오기

  1. Google Drive API를 사용하여 Apps Script가 생성한 PDF 파일을 검색하고 다운로드합니다.
  2. 파일의 ID나 이름을 알고 있다면, Files.get 메서드로 파일 메타데이터를 가져온 후 GoogleCredential을 사용하여 인증된 Drive 서비스 객체로 파일을 다운로드할 수 있습니다.
Posted by yongary
,

springFramework의 BeanUtils말고 apache의 BeanUtils를 상속해서 NullAwareBeanUtils를 만들면 된다.

import org.apache.commons.beanutils.BeanUtilsBean;

public class NullAwareBeanUtilsBean extends BeanUtilsBean {

    @Override
    public void copyProperty(Object dest, String name, Object value) throws IllegalAccessException, InvocationTargetException {
        if(value == null) return; // null 값이면 복사를 수행하지 않음
        super.copyProperty(dest, name, value);
    }
}

사용법:
NullAwareBeanUtilsBean nullAwareBeanUtils = new NullAwareBeanUtilsBean();
nullAwareBeanUtils.copyProperties(destObject, sourceObject);
Posted by yongary
,

selenium은 웹 내부만 자동화 해주는데 웹에서 뭘 진행하다 보면 exe파일로 앱이 떠야하는 경우가 있는 사이트의 경우 앱 클릭까지 자동화하는 방법:

 

웹 애플리케이션 테스트를 위해 Selenium을 사용하는 경우, Selenium은 브라우저 내에서 동작하는 웹 페이지의 자동화에 최적화되어 있습니다. 그러나 웹 페이지에서 특정 동작을 통해 외부 애플리케이션(예: .exe 파일)을 실행해야 하는 경우, Selenium만으로는 이를 직접 제어할 수 없습니다.

웹에서 실행되는 애플리케이션(예: 파일 다운로드 후 실행 등)을 자동화하고자 한다면, 다음과 같은 방법을 고려할 수 있습니다:

1. 키보드 및 마우스 제어를 위한 도구 사용

  • AutoIt 또는 Sikuli: 이러한 도구들은 시스템 수준에서의 GUI 자동화를 가능하게 해줍니다. 예를 들어, 파일 다운로드 대화 상자의 조작, .exe 파일 실행, 애플리케이션 내의 특정 버튼 클릭 등의 작업을 스크립트를 통해 자동화할 수 있습니다.
  • 이 도구들은 스크립트로 작성된 시나리오에 따라 키보드 입력, 마우스 클릭 및 이동을 시뮬레이션할 수 있으며, 화면 상의 이미지를 기반으로 특정 요소를 인식하고 조작할 수 있는 기능도 제공합니다.
  • Selenium과 함께 사용하여, Selenium이 웹 페이지 내의 자동화를 담당하고 AutoIt 또는 Sikuli가 외부 애플리케이션의 자동화를 담당하도록 할 수 있습니다.

2. Selenium과 외부 도구의 통합

  • 웹 자동화 과정에서 특정 단계에서 외부 애플리케이션을 실행해야 한다면, Selenium 스크립트 내에서 AutoIt 또는 Sikuli 스크립트를 호출하여 실행할 수 있습니다.
  • 예를 들어, Python을 사용하는 경우, subprocess 모듈을 사용하여 AutoIt 스크립트를 실행할 수 있습니다.

예제: Python에서 AutoIt 스크립트 실행

 
import subprocess

# AutoIt 스크립트 실행
subprocess.run(['path/to/autoit/script.exe'])

 

예제:  AutoIt 스크립트

; 메모장을 실행합니다.
Run("notepad.exe")

; 메모장의 창이 활성화될 때까지 기다립니다.
WinWaitActive("제목 없음 - 메모장")

; 텍스트를 입력합니다.
Send("Hello, World!{ENTER}")
Send("이것은 AutoIt 스크립트에 의해 자동으로 입력된 텍스트입니다.")



; 사용자에게 경고창을 표시합니다.
MsgBox(0, "경고", "이것은 AutoIt 스크립트입니다!")



; 특정 응용 프로그램 실행
Run("your_application.exe")

; 응용 프로그램 창이 나타날 때까지 기다립니다.
WinWaitActive("응용 프로그램 제목")

; 'OK' 버튼을 클릭합니다.
ControlClick("응용 프로그램 제목", "", "[CLASS:Button; TEXT:OK]")

기본방법 

  1. AutoIt을 설치합니다.
  2. 파일을 .au3 확장자로 저장합니다.
  3. 저장한 스크립트 파일을 더블 클릭하거나, AutoIt 스크립트 편집기에서 직접 실행하여 테스트합니다.

AutoIt 스크립트는 GUI 기반의 애플리케이션 자동화에 매우 유용하며, 복잡한 작업을 간단한 스크립트로 자동화할 수 있습니다. 스크립트는 상황에 맞게 수정하여 사용해야 합니다. 예를 들어, "응용 프로그램 제목"이나 "your_application.exe"는 실제 사용하는 응용 프로그램의 이름이나 실행 파일 경로로 변경해야 합니다.

 

오토잇 설치 가이드: https://mypcinfo.tistory.com/23  (2019년 글) 

Selenium+오토잇:   https://testmanager.tistory.com/145  (2018년 글)

 

 

 

Python에서 Selenium과 Sikuli를 함께 사용하여 GUI 자동화 작업을 수행하는 예제.

 

Sikuli의 기능을 Python 스크립트 내에서 직접 호출하기 위해서는 Sikuli의 명령줄(Command Line) 인터페이스를 사용하거나 SikuliX API (Java 기반)를 Python과 연동하는 방법이 있습니다. 여기서는 가장 간단한 방법 중 하나인 Sikuli Script를 외부 프로세스로 실행하는 방법을 사용합니다.

이 예제에서는 Selenium을 사용하여 웹 브라우저를 자동으로 제어하고, 특정 조건에서 Sikuli 스크립트를 호출하여 브라우저 외부의 GUI 요소를 제어하는 상황을 가정합니다. 예를 들어, Selenium으로 파일 다운로드 버튼을 클릭한 후, Sikuli를 사용하여 나타나는 시스템 파일 다이얼로그를 제어할 수 있습니다.

준비사항

  1. Python, Selenium, SikuliX가 설치되어 있어야 합니다.
  2. SikuliX IDE를 사용하여 Sikuli 스크립트를 작성하고 저장합니다. 예를 들어, saveFile.sikuli이라는 이름으로 저장합니다.

Sikuli 스크립트 예제

  • saveFile.sikuli 스크립트는 다운로드 창에서 "저장" 버튼을 클릭하는 작업을 수행할 수 있습니다.
from selenium import webdriver
import subprocess
import time

# Selenium으로 웹드라이버 초기화 및 웹페이지 열기
driver = webdriver.Chrome()
driver.get('http://example.com')

# 웹 페이지에서 파일 다운로드를 시작하는 동작 수행 (Selenium 사용)
download_button = driver.find_element_by_id('download')
download_button.click()

# 파일 다운로드 다이얼로그 처리를 위해 Sikuli 스크립트 호출 (외부 프로세스 실행)
time.sleep(5)  # 다운로드 다이얼로그가 나타나기를 기다림
sikuli_script_path = 'C:\\path\\to\\saveFile.sikuli'
subprocess.call(['C:\\path\\to\\runsikulix.cmd', '-r', sikuli_script_path])

# 작업 완료 후 브라우저 닫기
driver.quit()

 

이 예제에서는 subprocess.call을 사용하여 Sikuli 스크립트를 외부 프로세스로 실행합니다. SikuliX를 설치한 디렉토리 내의 runsikulix.cmd(Windows의 경우)를 사용하여 Sikuli 스크립트를 실행합니다. Sikuli 스크립트 경로와 SikuliX 실행 파일 경로는 실제 환경에 맞게 수정해야 합니다.

주의사항

  • Sikuli 스크립트를 실행하기 전에, 필요한 경우 시스템 다이얼로그가 화면에 완전히 나타날 때까지 충분한 대기 시간을 제공해야 합니다.
  • Sikuli 스크립트의 이미지 인식은 실행 환경의 해상도, 디스플레이 설정, UI 테마 등에 영향을 받을 수 있으므로, 환경에 따라 인식률이 달라질 수 있습니다.

 

Posted by yongary
,

 

  • 설치:  pip install requests
  • 예제: 
import requests

# GET 요청 보내기
def send_get_request(url):
    try:
        response = requests.get(url)
        if response.status_code == 200:
            # 요청이 성공하면 JSON 형식으로 반환된 데이터를 파싱하여 반환합니다.
            return response.json()
        else:
            print(f"Failed to send GET request. Status code: {response.status_code}")
            return None
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

# POST 요청 보내기
def send_post_request(url, data):
    try:
        response = requests.post(url, json=data)
        if response.status_code == 200:
            # 요청이 성공하면 JSON 형식으로 반환된 데이터를 파싱하여 반환합니다.
            return response.json()
        else:
            print(f"Failed to send POST request. Status code: {response.status_code}")
            return None
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

# 예제 URL
url = 'https://jsonplaceholder.typicode.com/posts/1'

# GET 요청 보내기
response_data = send_get_request(url)
if response_data:
    print("GET 요청 결과:")
    print(response_data)

# POST 요청 보내기 (예제 데이터)
post_data = {'title': 'foo', 'body': 'bar', 'userId': 1}
response_data = send_post_request(url, post_data)
if response_data:
    print("POST 요청 결과:")
    print(response_data)

 

물론 flask안에서도 동작한다.

Posted by yongary
,