[웹] 텔레그램 Bot 이용하기

telegram bot

Telegram bot

Telegram 은 @BotFather 를 제공하는데 @BotFather 를 통해 간단히 Bot 을 만들 수 있다.

Bot 만들기

  1. @BotFather 와 대화를 시작한다
  2. /newbot
  3. "bot 이름" / "user 이름" 을 알려준다
  4. bot 이 만들어지고, access token 을 알려준다.


Bot 에 메시지 보내기

telegram 에서 bot 을 등록한다.(찾기에서 "bot 이름" 을 치면 나온다.)

getUpdates 를 하면 chat_id 를 얻을 수 있다.

  1. bot 을 등록하지 않으면, update 할 내용이 없어서, 아무런 내용이 나오지 않는다. 그래서 chat_id 를 얻을 수 없다.
  2. https://api.telegram.org/bot<token>/getUpdates

telegram 에 메시지 보내기

  1. https://api.telegram.org/bot<token>/sendMessage?chat_id=234324&text=helloworld

여러명에게 메시지 보내기

텔레그램에서 기본적으로 봇도 일종의 사람의 역할을 한다. 그래서 이 봇을 찾아서 등록 하는 것은 그 봇과 채팅방을 하나 여는 것이 된다. 이때 chat id 가 생긴다.

처음에 필자가 오해했던 부분은 봇을 등록하기만 하면 모두에게 문자가 갈 것이라 생각했다. 하지만 지정된 채팅방(chat id) 로만 보낸다. 그래서 만약 단체알림의 용도로 쓰고 싶다면 이 봇이 참여한 그룹을 하나 만들어야 한다. 그리고 알람을 받을 인원을 이 그룹에 참여시켜야 한다. 그리고 봇이 이 그룹채팅방(chat id)에 문자를 보내도록 해야 한다.

Get TELEGRAM Channel/Group ID, StackOverflow 에 나온 것처럼 web telegram 을 이용하면, 쉽게 group chat id 를 알 수 있다.

조심할 점은 group 이 super group 으로 자동으로 변경되는 경우가 있다. 이때는 chat id 가 변경되기 때문에 api 의 parameter 에 쓰이는 chat_id 값도 변경이 필요하다.

전송방식

Bot <--> Someone

아래 4가지 방식으로 message 를 보내고 받을 수 있다.(UTF-8 이다.)

  1. URL query string
  2. application/x-www-form-urlencoded
  3. application/json (except for uploading files)
  4. multipart/form-data (use to upload files)

전송 한계


API 가 초당 한 user에게 최대 30개의 문자(30 messages) 만 보낼 수 있게 되어 있다. 이 이상보내면 429 error 가 뜬다.

그리고 같은 group 으로 보내는 메시지는 1분에 20개 이상은 안된다.

이것을 피하려면 하나의 알림에 대해 여러개의 bot 을 사용해야 할 듯 하다. 또는 보내는 message 를 모아서 한번에 보내면 된다. 대략 3초에 1번 정도만 send 를 한다.

한번에 보낼 수 있는 길이는 4096 UTF character 이다. 너무 긴 글자를 보내면 400 error code 가 뜬다.

update 받는 방식

Someone --> Bot


이건 누군가가 bot 에게 보낸 내용을 확인하는 방법이다. 이것은 텔레그램 client 채팅방 같은 것을 구성할 때 필요하다고 보면 된다. client 를 구성하려면 상대가 한 이야기를 가져와야 한다. 그 방법을 제공하는 것이다.

또는 텔레그램을 통해서 서버에 명령을 내리거나 하는 기능을 구현할 때 등에 사용해도 된다.

2중 한개를 쓰면 다른 하나는 사용이 안된다.

  1. getUpdates : pull, 이녀석은 우리가 호출할 때 bot 이 받은 내용을 알려주는 것이고,
  2. setWebhook : push, 이 녀석은 메시지가 오면 자동으로 특정 url 로 날려주게 설정해서 사용할 수 있다. 그래서 이녀석의 사용을 위해서는 server 가 필요하다.

setWebhook


bot 설정 변경

이름 변경

  1. @BotFather 에서 /setuserpic을 치면, 현재 소유한 bot 들이 나온다. 
  2. 그러면, 이제 bot 을 선택하면, 
  3. image 를 send 해달라고 메시지가 나온다.
  4. image 를 보내면 된다.(채팅창에서)

기타 변경

@BotFather 에서 /help 를 치면 가능한 명령어가 나온다.

  • /setname - change a bot's name
  • /setdescription - change bot description
  • /setabouttext - change bot about info
  • /setuserpic - change bot profile photo
  • /setcommands - change the list of commands
  • /deletebot - delete a bot
  • /mybots - 내가 만든 모든 bot 들이 보인다. 여기서 bot 을 선택하면 Bot Settings 를 메뉴가 나온다.
    • group privacy : group 안에 있을 때 privacy mode 일때는 '/'로 시작되는 message 만 받게 된다. admin 인 경우는 모든 message 를 수신한다.(Bots: privacy mode)
    • allow groups: group 에 초대가 안되게 할 수 있다.

[컴][웹] AWS 요금

email 서버 금액 / aws 요금 / 아마존 요금


Amazon 요금

Amazon SES pricing


상황 지불 추가요금
이메일을 Amazon EC2 에서 보내면 매달 62,000 건까지 무료, 초과 1,000 건 당 $0.1 첨부파일들 전체용량 1GB 당 $0.12 를 지불
EC2 외에 다른곳에서 보내면 1,000 건 당 $0.1  첨부파일들 전체용량 1GB 당 $0.12 를 지불
이메일 수신 총 1,000 건 수신은 무료, 그 이후부터는 1,000 건 당 $0.1 매 수신하는 256MB에 대해 $0.09 을 지불.( 1,000개의 incoming email chunks(256 kilobytes (KB)) )








[컴][웹] vscode remote debugger 를 remote node server 에 attach 하기

원격 서버에 붙이기 / 디버거 붙이기 노드서버에 붙이기 / agent forwarding

vscode remote debugger 를 remote node server 에 attach

ssh tunneling

ref. 1 에서 추천하는 방법인데, remote server 에서 debugging 을 위해 모든 ip address 로 부터의 접근을 허락하는 것은 위험하니, remote server 는 9229 만 debugging 용으로 열어놓고, 접근하는 쪽에서 ssh tunneling 을 열어서 debugging 을 하라는 이야기다.

하지만 여전히 debugging port 를 열어놓는 것은 좋지 않은 행위이니, 실서버에서의 사용은 자제하는 것이 좋다.

server 에서 debugging mode 로 실행

$ node --inspect server.js
Debugger listening on ws://127.0.0.1:9229/3ee2ba78-e563-4f9a-9fa1-06e8b6bb8539
For help, see: https://nodejs.org/en/docs/inspector

ssh tunneling 실행

먼저 ssh tunneling 을 열어놓는다.

ssh -N -L 9221:localhost:9229 myhome@ec2-174-69-46-3.ap-northeast-.compute.amazonaws.com -i .\ec2-dev.pem

ssh <bastion_server_connect_info> -N -L <source_port>:<destination_ip>:<destination_port>

localhost:<source_port> 로 요청하면, ec2-174-69-46-3.ap-northeast-.compute.amazonaws.com:<destination_port> (ssh tunnel) 을 타고, <destination_server>:<destination_port> 로 가게 된다.

vscode

그리고 vscode 에서 source 를 열어놓고, 아래 debug option 을 선택해서 실행하면 된다.

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [

        
        ...
        {
            "type": "node",
            "request": "attach",
            "name": "Attach to Remote",
            "address": "localhost",
            "port": 9221,
            "localRoot": "${workspaceFolder}",
            "remoteRoot": "/home/myhome/myserver"
        }
    ]
}


See Also

  1. ssh man page
  2. 쿠…sal: [컴] ssh tunneling

References

  1. Debugging - Getting Started | Node.js

[컴][웹] AWS CLI 로 s3 에 파일 업로드 하기

file upload / upload files / how to back up using aws cli with s3

AWS s3 에 파일 upload

AWS CLI 설치

update 2023-01:

v1 에 대한 설치:

여기서는 virtual env 를 이미 만들었다는 가정하에 작업을 한다.(가상환경 설정은 여기 를 참고하자.)

pip install awscli --upgrade

설치가 완료되면, aws --version 으로 설치가 잘 됐는지를 확인할 수 있다.

(mycli) c:\a\envs\mycli\Scripts>aws --version
aws-cli/1.16.114 Python/3.6.3 Windows/10 botocore/1.12.104

aws configure

aws configure 를 통해서 access key 랑 access key ID 를 설정하게 된다. region 정보는 여기서 보고 정해주자(region 정보) output format 의 기본값은 json 이다.

(mycli) c:\a\envs\mycli\Scripts>aws configure
AWS Access Key ID [None]: ADDFSDFDSFSKI
AWS Secret Access Key [None]: Tqq+DeDFSDFFDggf2cptQ3e/gn
Default region name [None]: ap-northeast-2
Default output format [None]: json

아래처럼 profile 을 설정할 수 있다. 'myprofile' 이라는 이름의 profile 을 만든다.

aws configure --profile myprofile

access key

IAM 에서 user 를 만들면 access key 와 secret access key 를 얻게 된다. 이때 policy AmazonS3FullAccess 만 추가해 주면 된다.

TCP port 443

AWS CLI는 TCP 포트 443에서 HTTPS를 사용하여 AWS 서비스에 요청한다고 한다. 그래서 방화벽에서 이부분의 제한이 걸려있는지 확인이 필요하다.

aws s3 cp

이제 aws cli 를 사용해서 upload 를 해보자. my-first-backup-bucket 라는 bucket 에 'my first backup.bak' 를 upload 하는 경우라면 아래처럼 하면 된다.

aws s3 cp "C:\users\my first backup.bak" s3://my-first-backup-bucket/
aws s3 cp "C:\users\my first backup.bak" s3://my-first-backup-bucket/ --profile myprofile

삭제는 아래처럼 하면 된다.

aws s3 rm s3://my-first-backup-bucket/

참고로 같은 이름의 파일을 올리면 overwrite 된다.

See Also

  1. s3 — AWS CLI 1.16.114 Command Reference
  2. 쿠...sal: [컴] aws IAM 에서 계정 만들기

[컴] iOS 보안-시스템 보안

iOS 부팅 절차 / boot time / booting process / enclave


ref. 1 의 System Security 의 일부를 번역했다. 자세한 내용은 ref. 1을 보도록 하자.

iOS 보안-시스템 보안

기기암호화(device encryption) 는 기본적으로 설정되어 있으며, 설정을 변경할 수 없다.

Secure Boot Chain

  1. iOS 켜기
  2. --> AP 가 Boot ROM 의 code실행
    1. the hardware root of trust 라고 알려져 있다.
    2. the chain of trust 의 첫번째 단계(first step) 이다.
    3. 이 code 는 변경불가능(immutable code)
    4. 칩제조(chip fabrication) 때 만들어 진다.
    5. implicitly trusted
    6. Apple Root CA public key 를 가지고 있다.
      1. 이 public key 는 iBoot bootloader 가 load 되기 전에 Apple 에 의해 서명(sign) 됐다는 것을 확인(verify) 하는데 사용된다.(아래 boot-time verification 참고.)
  3. Boot ROM 에 의해 추가적인 Low-Level Bootloader(LLB) stage 가 load 되고, 확인(verify) 된다.
    1. A9를 포함한 A9 이전의 A시리즈 processor 에만 존재.
  4. 만약 Boot ROM 이 LLB 또는 iBoot 을 load 하는 것을 실패하면,  기기는 DFU mode (Device Firmware Upgrade)로 들어가게 된다.
    1. 오래된 기기들에서 LLB 를 load 하는 것을 실패 하거나,
    2. 새로운 기기들에서 iBoot 을 load 하는 것을 실패하는 것
  5. LLB 나 iBoot 이 다음 작업(next step) 을 load 하거나 verify 하는 것을 실패하는 경우
    1. startup 은 멈춰지고(halt) iTunes 에 접속하라는 화면이 보여진다. 
    2. --> recovery mode 이다.
  6. DFU mode 로 가거나, recovery mode 로 들어가면, USB 를 이용해서 iTunes 에 접속해서 "공장 기본 세팅(factory default settings)" 로 복구되어 져야만 한다.
  7. 기기가 Recovery Mode 와 DFU Mode 로 들어가기 전에 The Boot Progress Register (BPR) 가 update 된다. 이 update 된 값을 보고 Secure Enclave 가 user data 에 대한 접근제한을 하게 된다.
    1. Recovery Mode
      1. A10, S2 그리고 최신의 SoCs 를 가진 기기에서 iBoot 에 의해 BPR 이 set.
    2. DFU Mode : A12 SoC 를 가진 기기에서 Boot ROM 에 의해 BPR 이 set.
  8. --> iBoot 이 일들을 마치면
  9. --> iBoot 은 iOS kernel 을 확인(verify) 하고, 실행한다.

baseband subsystem 또한 이것과 비슷한 자신의 secure booting 을 이용한다.
Secure Enclave coprocessor 또한 secure boot process 를 이용하고, 그로인해 그것의 분리되 소프트웨어가 verified and signed by Apple 되었다는 것을 확신시켜준다.
secure boot



시스템 소프트웨어 권한부여(System Software Authorization)

만약 과거버전의 iOS의 설치가 가능하다면 해커는 과거버전의 iOS를 깔고 권한을 가져올 수 있다. 이것을 막기 위해서 iOS는 System Software Authorization 을 이용한다. Secure Enclave 도 이것을 이용한다.


iOS update

iOS update 는 2가지 방식(iTunes, OTA) 으로 가능하다.
  • iTunes 로 업데이트를 할 때
    • iOS image 전체를 download 
    • Content Caching 옵션을 켠 macOS High Sierra 를 돌리는(run) Mac 을 사용한다면, 미리 cache 되어서, iOS 의 update 를 바로 할 수 있게 해준다.
  • OTA 로 할 때: patch 를 할 내용만 다운로드한다. 

installation authorization server

iOS update 할때 기기는 Apple 의 installation authorization server 에 접근한다.
그리고 다음 3가지를 확인 한다.
  1. bundle의 measurements: 설치될 installation bundle들에 대한 암호화된 measurements(측정)
    • installation bundle : iBoot, kernel, iOS Image
  2. nonce : signed data 를 가져다 다른 기기에 쓰는 것을 막아주고, system software 를 변경하지 못하게 막는다.
  3. ECID: 기기의 고유한  ECID(Exclusive Chip Identification) 를 서버로 보내게 된다.

installation authorization server 에서 하는일

서버에서는  이 installation bundle 의 버전들이 맞는 구성인지를 확인한다. 예를 들면 특정버전의 iBoot 은 특정 version 의 kernel 을 써야만 하는식이다. 이렇게 버전이 맞으면 이 measurement 에 ECID 를 더해서 sign 을 하고 이 sign 된 data 를 기기에 보내준다.
sign(measurment + ECID) ---> device

boot-time verification

위에 설명한 startup process 가 "Apple 이 sign 한 code" 만 기기에 설치되는 것을 보장해 준다.
  • Apple 의 signature : boot time 에 일어나는 chain-of-trust evaluation 은 Apple 의 signature 를 verify 한다.
  • disk 에서 load 되는 item 의 measurement: "disk 에서 load 되는 item 의 measurement (기기의 ECID를 이용해서 만들어져 있다.)"와 "signature 에 의해 감싸진 measurement(위의 installation authorization server 에서 받은)"가 맞는지를 verify 한다.
이 절차들이 특정기기에 대한 authorization 을 해주고, 기기에서 옛 iOS버전이 다른 곳으로 copy 안되도록 한다.

Secure Enclave

  • Secure Enclave 는 보조 프로세서이다. 
  • SoC 안에 들어있다.(fabricated)
  • 암호화된 메모리를 사용
  • 하드웨어 난수발생기(random number generator) 를 포함.
  • Secure Enclave Boot ROM
    • application processor Boot ROM 과 비슷하게, Secure Enclave Boot ROM 은 변경이 불가능한 code (immutable code) 이다. Secure Enclave 를 위한 "하드웨어 root of trust" 를 확립한다.(establish)
    • device 가 시작될 때, Secure Enclave Boot ROM 이 수명이 짧은 메모리 보호 키(ephemeral memory protection key)를 만든다. 
  • Secure Enclave 는 데이터 보호 키 관리에게 (Data Protection key management) 모든 암호화 기능(cryptographic operations)들을 제공
  • 심지어 커널이 허락한 상태에도(kernel has been compromised) Data Protection 의 integrity (데이터가 변경, 파괴되지 않은 상태)을 유지.
  • AP(Application processor) 와 Secure Enclave 사이의 통신은 interrupt-driven mailbox 와 shared memory data buffer 들과 분리되어 있다.
  • Secure Enclave OS 를 실행
    • Secure Enclave OS
      • "L4 마이크로 커널의 Apple-customized version" 에 기초해서 만들어진 OS
      • Apple 에 의해 sign 된다.
      • Secure Enclave Boot ROM 가 verify
      • 개인의 소프트웨어 업데이트 프로세스를 통해 update 된다.
  • device 가 시작될 때, Secure Enclave Boot ROM 이 수명이 짧은 메모리 보호 키(ephemeral memory protection key)를 만든다. 
    • 이 키(memory protection key)는 기기의 UID 와 얽히게 만들고(entangle), 기기의 memory space 의 "Secure Enclave 부분"을 암호화 할 때 사용된다.
    • 예외적으로 Apple 의 A7 에선, Secure Enclave memory "memory protection key" 로도 인증(authenticated) 이 가능하다. A11과 A11 이후 그리고 S4 SoC 들에서는 "memory protection key" 와 on-chip SRAM 에 저장된 nonce 들에 의해 인증된다.(authenticated)
    • 그리고, A11과 A11 이후 그리고 S4 SoC 들에서 integrity tree 는 보안이 중요한 Secure Enclave memory 의 replay 를 막기위해 사용되어진다.
    Secure Enclave 에 의해 file system 에 저장된 data 는 UID 와 entangled 된 key와 anti-replay counter 로 암호화되어 진다. anti-replay counter 는 dedicated 비휘발성 메모리 IC 안에 저장되어 있다.

    A12 와 S4 SoC 들이 있는 기기들에서, Secure Enclave 는 anti-replay counter storage 를 위해 secure storage IC 와 짝을 이룬다. secure storage IC 는 immutable ROM code, 하드웨어 random number generator, 암호화엔진들, physical tamper detection(물리적인 조작 감지) 과 함께 디자인됐다. counter 들을 읽고 업데이트 하기 위해서, Secure Enclave 와 storage IC 는 counter 들에게 exclusive access 를 보장하는 '안전한 protocol '를 사용한다.

    Secure Enclave 의 "anti-replay 서비스"들은 event 에 사용된 data 의 철회(revocation of data over events)를 위해 사용되어진다.

    이 이벤트들은 anti-replay 의 경계들(boundaries)을 표시 해 준다.
    이벤트는 다음것들을 포함한다. 하지만 제한되진 않는다.
    • Passcode change
    • Touch ID or Face ID enable/disable
    • Fingerprint add/delete
    • Face ID reset
    • Apple Pay card add/remove
    • Erase All Content and Settings
    Secure Enclave 는 또한 지문을 처리하고, Touch ID 와 Face ID 센서들로 부터 오는 얼굴데이터를 처리하는 책임도 진다. 그리고 맞는지 여부를 결정하고, 그리고나서, 유저를 대신해서 access 또는 구매를 가능하게 한다.

    See Also

      1. Apple T2 보안 칩-Mac 보안

        Reference

        1. https://www.apple.com/business/site/docs/iOS_Security_Guide.pdf

        [컴][웹] AdoniJS at Start up

        아도니스 제이에스 / js


        Adonisjs at startup

        app.js

        _loadPreLoadFiles 이전에 this._registerProviders()와 await this._bootProviders()를 호출한다. 이 때 app.js 에 접근해서 Providers 를 가져오고, 이 Provider 의 register() 와 boot() 을 호출한다.

        preloaded files

        아도니스js 에서 처음에 load 하는 file 들은 다음과 같다.(_loadPreLoadFiles)
        • 'start/routes',
        • 'start/events',
        • 'start/socket',
        • 'start/kernel',
        • 'start/wsKernel'
        이 부분은 Ignitor source 에서 확인할 수 있다.
        new Ignitor(require('@adonisjs/fold'))
          .appRoot(__dirname)
          .fireHttpServer()
          .catch(console.error)
        
        
        
        class Ignitor {
          constructor (fold) {
            this._fold = fold
            this._appRoot = null
            this._modulesRoot = null
            this._loadCommands = false
        
            /**
             * Files to be preloaded
             *
             * @type {Array}
             */
            this._preLoadFiles = [
              'start/routes',
              'start/events',
              'start/socket',
              'start/kernel',
              'start/wsKernel'
            ]
        
            /**
             * Default app file
             *
             * @type {String}
             */
            this._appFile = 'start/app.js'
            ...
          }
          ...
          async fire () {
           ...
           this._registerProviders()
           await this._bootProviders()
           ...
           this._loadPreLoadFiles()
          }
        
          async fireHttpServer (httpServerCallback) {
            try {
              await this.fire()
              await this._startHttpServer(httpServerCallback)
            } catch (error) {
              this._printError(error)
            }
          }
        
          /**
           * Return the exported values from the appFile. Also
           * it will validate the exports object to have all
           * required keys.
           *
           * @method _getAppAttributes
           *
           * @return {Object}
           *
           * @private
           */
          _getAppAttributes () {
            return require(path.join(this._appRoot, this._appFile))
          }
        
          /**
           * Registers an array of providers to the Ioc container. This
           * method will make use of the `appFile` to get the providers
           * list.
           *
           * @method _registerProviders
           *
           * @return {void}
           *
           * @private
           */
          _registerProviders () {
            this._callHooks('before', 'providersRegistered')
        
            /**
             * Getting list of providers and registering them.
             */
            const { providers, aceProviders } = this._getAppAttributes()
            const providersToRegister = this._loadCommands ? providers.concat(aceProviders) : providers
            this._fold.registrar.providers(providersToRegister).register()
        
            debug('registered providers')
            this._callHooks('after', 'providersRegistered')
          }
        
          /**
           * Boot providers
           *
           * @method _bootProviders
           *
           * @return {void}
           *
           * @async
           *
           * @private
           */
          async _bootProviders () {
            this._callHooks('before', 'providersBooted')
        
            /**
             * The providers set set on `registrar` when they were registered. We
             * use the same set to boot the previously registered providers.
             */
            await this._fold.registrar.boot()
        
            debug('booted providers')
            this._callHooks('after', 'providersBooted')
          }
        
          ...
          _loadPreLoadFiles () {
            this._callHooks('before', 'preloading')
            ...
        
            this._preLoadFiles.forEach((file) => {
              const filePath = path.isAbsolute(file) ? file : path.join(this._appRoot, file)
        
              /**
               * Require file when it's not optional or when optional
               * file exists
               */
              if (!this._isOptional(file) || this._fileExists(filePath)) {
                require(filePath)
              }
            })
        
            this._callHooks('after', 'preloading')
          }
        }
        



        [컴][웹] laravel 에서 큰 Database result 를 처리할 때




        Laravel 에서 큰 Database result 를 처리할 때

        아래 글들을 참고하면 된다. 관련 source code 도 확인할 수 있다.

        Fatal error: Allowed memory size of 37748736 bytes exhausted (tried to allocate 72 bytes) in /home/cocktail/apps/cocktail_lumen/vendor/illuminate/database/Eloquent/Model.php on line 279
        

        chunk vs cursor

        chunk 를 사용하면 일반적은 get() 을 사용하는 것보다 memory 를 많이 아낄 수 있다. 이보다 더 확실히 아낄 수 있는 것은 cursor 를 사용하는 것이다.