Signal, Nostr, IRC
프라이버시 우선 및 탈중앙화 채널의 인증 방식과 기능 플래그 상세 안내.
이 페이지는 Revka가 지원하는 세 가지 프라이버시 우선 · 탈중앙화 채팅 채널의 레퍼런스입니다. Signal(로컬 signal-cli 데몬 브리지 경유), Nostr(NIP-04 및 NIP-17 암호화 DM을 지원하는 탈중앙화 릴레이 프로토콜), IRC(TLS 기반, SASL 및 NickServ 인증 지원)를 다룹니다. 세 채널 모두 대화를 중앙화된 벤더 API에 맡기지 않습니다. Signal은 로컬에서 브리지하는 암호화 인프라를 통해 동작하고, Nostr는 계정 서버 없이 릴레이 기반으로 동작하며, IRC는 사용자가 선택한 서버에 직접 연결합니다. 정확한 설정 키, 인증 흐름, 전달 동작, Nostr 빌드 요구 사항이 필요할 때 이 페이지를 참고하세요.
세 채널 모두 ~/.revka/config.toml의 [channels_config] 아래에서 설정합니다. 파일을 직접 편집하거나 revka onboard --channels-only를 실행한 뒤, 데몬을 재시작하여 변경 사항을 적용하세요. 모든 채널이 공유하는 트레이트 모델, 전달 모드, 허용 목록 시맨틱스는 채널 개요를 참고하세요.
한눈에 보기
섹션 제목: “한눈에 보기”| 채널 | 수신 방식 | 공개 인바운드 포트 | 빌드 기능 플래그 |
|---|---|---|---|
| Signal | signal-cli SSE 브리지 | 없음 | — |
| Nostr | 릴레이 WebSocket | 없음 | channel-nostr |
| IRC | TLS 소켓 | 없음 | — |
세 채널 모두 공개 인바운드 포트가 필요하지 않습니다. 각 채널은 외부(로컬 signal-cli 데몬, Nostr 릴레이, IRC 서버)로 연결을 시작합니다. 빌드 시 기능 플래그로 제어되는 채널은 Nostr뿐입니다.
Signal
섹션 제목: “Signal”Signal 채널은 Signal 서버와 직접 통신하지 않습니다. 로컬에서 실행 중인 signal-cli 데몬에 HTTP로 브리지합니다. /api/v1/events에서 Server-Sent Events(SSE)로 수신 메시지를 수신하고, /api/v1/rpc에서 JSON-RPC로 답장을 전송합니다. 다이렉트 메시지와 Signal 그룹을 모두 지원하며, 타이핑 인디케이터도 전달합니다.
사전 조건: signal-cli를 데몬 모드로 실행
섹션 제목: “사전 조건: signal-cli를 데몬 모드로 실행”signal-cli를 설치하고 번호를 등록(공식 문서 참고)한 뒤, HTTP 데몬 모드로 시작합니다.
signal-cli -a +1234567890 daemon --http 127.0.0.1:8686Revka는 해당 HTTP 엔드포인트에 연결합니다. 브리지는 메시지 전송 시 JSON-RPC send 요청을, 타이핑 인디케이터 전송 시 sendTyping을 보내고, /api/v1/check로 상태를 확인합니다.
Signal 설정
섹션 제목: “Signal 설정”[channels_config.signal]http_url = "http://127.0.0.1:8686"account = "+1234567890"group_id = "" # "" / omit = all; "dm" = DMs only; or a base64 group idallowed_from = ["*"]ignore_attachments = falseignore_stories = trueproxy_url = ""| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
http_url | string | — | 실행 중인 signal-cli HTTP 데몬의 베이스 URL. 필수. 후행 슬래시는 자동으로 제거됩니다. |
account | string | — | E.164 형식의 등록된 Signal 번호(+1234567890). 필수. account 쿼리/RPC 파라미터로 전달됩니다. |
group_id | string | 미설정 | 그룹 필터. 생략/미설정 시 DM과 그룹 모두 허용; "dm"은 다이렉트 메시지만 허용; 특정 base64 그룹 ID를 입력하면 해당 그룹만 허용합니다. |
allowed_from | array | — | 허용할 발신자 목록. []는 전체 거부; ["*"]는 전체 허용; 그 외에는 E.164 번호(또는 UUID — 아래 참고)를 나열합니다. |
ignore_attachments | bool | false | true로 설정하면 텍스트 본문 없이 첨부 파일만 있는 메시지를 건너뜁니다. |
ignore_stories | bool | false | 수신되는 Signal 스토리 알림을 건너뜁니다. |
proxy_url | string | — | 전역 [proxy] 설정을 재정의하는 채널별 HTTP/HTTPS/SOCKS5 프록시(선택 사항). |
발신자 ID와 허용 목록
섹션 제목: “발신자 ID와 허용 목록”Signal은 발신자를 전화번호(sourceNumber, E.164) 또는 번호를 숨긴 프라이버시 활성화 사용자의 경우 UUID로 보고합니다. 채널은 E.164 번호를 우선 사용하고, 없으면 UUID를 사용합니다. allowed_from에는 발신자가 제시하는 형식에 맞춰 등록하세요. 다른 채널과 마찬가지로 []는 전체 거부, ["*"]는 전체 허용입니다. 먼저 ["*"]로 전달을 확인한 뒤 범위를 좁히세요.
DM vs 그룹 라우팅
섹션 제목: “DM vs 그룹 라우팅”채널은 메시지가 온 곳으로 답장합니다.
- DM은 발신자의 번호(또는 UUID)로 답장합니다.
- 그룹 메시지는 해당 그룹으로 답장합니다. 내부적으로 답장 수신자에
group:접두사가 붙어(예:group:<base64-id>) JSON-RPCsend가recipient대신groupId로 라우팅됩니다. 이 값은 인바운드 메시지에서 자동으로 추출되므로 직접 설정할 필요가 없습니다.
그룹 트래픽을 무시하고 다이렉트 메시지에만 응답하려면 group_id = "dm"을 사용하세요.
동작 참고 사항
섹션 제목: “동작 참고 사항”- SSE 리스너는 지수 백오프(시작 2초, 최대 60초)로 자동 재연결합니다.
- 타이핑 인디케이터는
sendTyping으로 전송되며, 중지 타이핑 호출은 없습니다. Signal 클라이언트는 약 15초 후 인디케이터를 자동 만료시킵니다. ignore_stories의 기본값은false입니다. 수신되는 Signal 스토리 알림을 건너뛰려면true로 설정하세요(설정 예시 참고).
Nostr
섹션 제목: “Nostr”Nostr 채널은 릴레이 WebSocket을 통해 탈중앙화 Nostr 네트워크에 연결합니다. 두 가지 개인 메시지 프로토콜을 지원하며, 발신자가 사용한 프로토콜과 동일한 방식으로 답장합니다.
- NIP-04 — 레거시 암호화 다이렉트 메시지(이벤트 kind 4).
- NIP-17 — 현대적인 gift-wrap 개인 메시지(이벤트 kind 1059). NIP-04보다 메타데이터를 더 잘 숨깁니다.
Revka가 이전에 수신한 적 없는 수신자에게 메시지를 보낼 때는 NIP-17을 기본값으로 사용합니다.
Nostr 설정
섹션 제목: “Nostr 설정”[channels_config.nostr]private_key = "nsec1..." # hex or nsec bech32relays = ["wss://relay.damus.io", "wss://nos.lol"]allowed_pubkeys = ["npub1..."] # [] = deny all, ["*"] = allow all| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
private_key | string | — | 봇 ID의 비밀 키(hex 또는 nsec bech32 형식). 필수. 중요한 비밀 값입니다 — 아래 키 보안을 참고하세요. |
relays | array | 아래 네 개의 릴레이 | 연결할 WebSocket 릴레이 URL(wss://). 생략하면 Revka가 기본 세트를 사용합니다. |
allowed_pubkeys | array | [] | 봇에 메시지를 보낼 수 있는 공개 키(hex 또는 npub). []는 전체 거부; ["*"]는 전체 허용. 유효하지 않은 키는 시작 시 유효성 검사에서 실패합니다. |
relays를 생략하면 Revka는 다음 기본 릴레이에 연결합니다.
relays = [ "wss://relay.damus.io", "wss://nos.lol", "wss://relay.primal.net", "wss://relay.snort.social",]기본값에 의존하지 않고 신뢰하는 네트워크를 고정하려면 relays를 명시적으로 설정하세요.
NIP-04 vs NIP-17
섹션 제목: “NIP-04 vs NIP-17”시작 시 채널은 공개 키로 주소가 지정된 kind 4(NIP-04)와 kind 1059(NIP-17 gift wrap) 모두를 구독합니다. 각 인바운드 메시지에 대해 발신자가 사용한 프로토콜을 기록하여 답장이 동일한 방식으로 이루어지도록 합니다.
- NIP-04 메시지는 그 자리에서 복호화되며, 이벤트의
created_at이 실제 타임스탬프입니다. - NIP-17 메시지는 gift-wrap으로 래핑되어 있습니다. Revka는 gift wrap을 풀고 내부 rumor를 읽습니다. 외부 래퍼의 타임스탬프는 프라이버시를 위해 의도적으로 지터링되어 있으므로, Revka는 리스너 시작 이후에 메시지가 도착했는지를 판단할 때 내부 rumor의 타임스탬프를 사용합니다.
allowed_pubkeys 외부의 공개 키에서 온 메시지는 복호화 처리 전에 로그에 기록되고 드롭됩니다. 복호화 또는 언래핑에 실패한 메시지는 로그에 기록되고 건너뜁니다.
키 보안
섹션 제목: “키 보안”private_key는 중요한 자격증명으로 취급하세요 — 이 키가 곧 봇의 Nostr ID입니다. 암호화된 시크릿 저장소가 활성화된 경우([secrets]에서 encrypt = true), Revka는 설정 로드 시 온디스크 SecretStore에서 private_key를 복호화합니다. 따라서 평문 대신 암호화된 상태로 config.toml에 저장할 수 있습니다. 시크릿, 페어링 & 기기 인증을 참고하세요.
IRC
섹션 제목: “IRC”IRC 채널은 TLS를 통해 IRC 서버에 연결하고, 선택적으로 SASL 및/또는 NickServ로 인증하며, 지정한 채널에 참가하여 채널과 프라이빗 메시지 모두의 PRIVMSG 트래픽을 중계합니다. IRC 클라이언트는 일반 텍스트만 렌더링하므로, Revka는 모든 인바운드 메시지에 스타일 안내를 앞에 붙여 모델이 평문으로만 답하도록 지시합니다 — Markdown, 표, 코드 펜스 없이.
IRC 설정
섹션 제목: “IRC 설정”[channels_config.irc]server = "irc.libera.chat"port = 6697nickname = "revka-bot"username = "revka" # defaults to nicknamechannels = ["#revka", "#help"]allowed_users = ["*"]server_password = "" # PASS, e.g. for a ZNC bouncernickserv_password = "" # NickServ IDENTIFYsasl_password = "" # SASL PLAIN (IRCv3)verify_tls = true| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
server | string | — | IRC 서버 호스트명. 필수. |
port | number | 6697 | 서버 포트. 표준 TLS 포트가 기본값입니다. |
nickname | string | — | 봇의 닉네임. 필수. |
username | string | nickname | IRC 사용자 이름(USER의 user 부분). 기본값은 nickname. |
channels | array | [] | 연결 후 JOIN할 채널 목록(예: ["#revka"]). |
allowed_users | array | — | 허용할 닉네임 목록(대소문자 구분 없이 매칭) 또는 ["*"]. []는 전체 거부. |
server_password | string | — | PASS 명령으로 전송됩니다. ZNC 같은 바운서에 유용합니다. |
nickserv_password | string | — | 등록 후 PRIVMSG NickServ :IDENTIFY에 사용할 비밀번호. |
sasl_password | string | — | SASL PLAIN 인증(IRCv3)용 비밀번호. |
verify_tls | bool | true | 서버의 TLS 인증서를 검증합니다. 켜둔 상태로 유지하세요. 자체 서명 인증서를 사용하는 서버를 테스트할 때만 비활성화하세요. |
연결은 항상 TLS를 사용합니다 — 평문 모드는 없습니다. verify_tls = true는 번들된 루트 저장소를 기준으로 서버 인증서를 검증하며, false로 설정하면 인증서 검증이 완전히 비활성화되므로 테스트 목적으로만 사용해야 합니다.
SASL 인증 (IRCv3)
섹션 제목: “SASL 인증 (IRCv3)”sasl_password가 설정되면, Revka는 채널 참가 전 IRCv3 capability 핸드셰이크 중에 SASL PLAIN으로 인증합니다.
- Revka가
CAP REQ :sasl을 전송합니다. CAP * ACK :sasl수신 시AUTHENTICATE PLAIN을 전송합니다.- 서버가
AUTHENTICATE +로 응답하면, 현재 닉과sasl_password로 생성한 base64 인코딩PLAIN자격증명을 전송합니다. 903(RPL_SASLSUCCESS) 수신 시CAP END를 전송하고 등록 절차를 진행합니다.
서버가 CAP * NAK :sasl(SASL 미지원)로 응답하면 Revka는 경고를 로그에 기록하고 SASL 없이 계속 진행합니다. SASL 실패(904, 905, 906, 907) 시 Revka는 실패 코드를 로그에 기록하고 무한 재시도 없이 capability 협상을 종료합니다.
NickServ 인증
섹션 제목: “NickServ 인증”nickserv_password가 설정되면, Revka는 등록 완료(001 / RPL_WELCOME numeric) 후 NickServ에 인증합니다.
PRIVMSG NickServ :IDENTIFY <nickserv_password>SASL과 NickServ는 독립적으로 동작합니다 — 둘 중 하나, 둘 다, 또는 아무것도 사용하지 않을 수 있습니다. 네트워크가 SASL을 지원한다면 채널 참가 전에 인증이 이루어지므로 SASL을 권장합니다. NickServ와 ChanServ로부터의 메시지는 에이전트에서 항상 무시됩니다.
연결 및 메시지 동작
섹션 제목: “연결 및 메시지 동작”- 채널 vs DM 답장. 채널(
#name또는&name)로 온 메시지는 해당 채널에서 답장하며 모델에<sender>컨텍스트를 붙여 전달합니다. 프라이빗 메시지는 발신자에게 직접 답장합니다. - 닉네임 사용 중. 닉이 이미 사용 중인 경우(
433/ ERR_NICKNAMEINUSE), Revka는_를 붙여 재시도합니다(예:revka-bot_). - 치명적 인증 오류.
464(ERR_PASSWDMISMATCH)는 비밀번호 불일치 오류로 연결을 종료합니다. - 킵얼라이브. 서버의
PING은 자동으로PONG으로 응답됩니다. - 긴 메시지. 답장은 IRC 512바이트 줄 제한을 지키기 위해 여러
PRIVMSG줄로 분할됩니다. 안전한 UTF-8 경계에서 분할하며, 내장된 줄바꿈은 별도의 줄이 되고 빈 줄은 제거됩니다. - 읽기 타임아웃. 300초 동안 데이터가 수신되지 않으면 연결이 끊긴 것으로 간주하며, 재연결은 채널 수퍼바이저가 처리합니다.
The channel-nostr feature flag
섹션 제목: “The channel-nostr feature flag”Nostr 지원은 Cargo 기능 channel-nostr 뒤에 컴파일되며, 이 플래그는 nostr-sdk 의존성을 추가합니다. Nostr는 기본 기능 세트에 포함되어 있지 않으며 표준 릴리스 바이너리에도 컴파일되어 있지 않습니다(기본 Cargo 기능은 observability-prometheus와 skill-creation이며, 릴리스 바이너리는 channel-matrix, channel-lark, whatsapp-web을 추가합니다). Nostr를 사용하려면 반드시 --features channel-nostr를 지정하여 빌드해야 합니다(예: cargo build --release --features channel-nostr). Signal과 IRC는 기능 플래그가 없으며 항상 컴파일됩니다.
Nostr를 명시적으로 포함하여 빌드하려면:
cargo build --release --features channel-nostr--no-default-features와 직접 선택한 기능 목록으로 빌드하는 경우, Nostr를 원한다면 channel-nostr를 다시 추가하세요. 채널 기능 플래그(Matrix, Lark, Nostr, WhatsApp Web, 음성 웨이크)의 전체 목록은 Cargo 기능 플래그 & ADR을 참고하세요.
허용 목록 시맨틱스
섹션 제목: “허용 목록 시맨틱스”각 채널은 인바운드 발신자를 제어하며, 플랫폼마다 다른 필드명을 사용합니다.
| 채널 | 허용 목록 필드 | 매칭 기준 |
|---|---|---|
| Signal | allowed_from | E.164 전화번호 또는 UUID |
| Nostr | allowed_pubkeys | 공개 키(hex 또는 npub) |
| IRC | allowed_users | 닉네임(대소문자 구분 없음) |
세 채널 모두 동일한 규칙이 적용됩니다.
- 빈 목록(
[])은 모든 발신자를 거부합니다. "*"항목 하나는 모든 발신자를 허용합니다.- 그 외에는 나열된 ID만 허용됩니다.
먼저 와일드카드로 봇이 연결되어 응답하는지 확인한 뒤, 프로덕션 환경에서는 명시적인 ID로 교체하세요.
저장된 시크릿
섹션 제목: “저장된 시크릿”암호화된 시크릿 저장소가 활성화된 경우([secrets] encrypt = true), Revka는 설정 로드 시 SecretStore에서 다음 채널 자격증명을 복호화하므로 config.toml에 암호화된 상태로 저장할 수 있습니다.
- Nostr:
private_key - IRC:
server_password,nickserv_password,sasl_password
Signal 채널은 암호화 가능한 토큰이 없습니다 — 자체 네트워크 인증을 수행하지 않으므로, 보안은 로컬 signal-cli 데몬의 바인딩에 의존합니다. 시크릿, 페어링 & 기기 인증과 보안 모델을 참고하세요.
관련 페이지
섹션 제목: “관련 페이지”- 채널 개요 — 채널 트레이트, 전달 모드, 허용 목록 모델.
- 메시징 채널 연결하기 — 채널 활성화를 위한 일반적인 흐름.
- Cargo 기능 플래그 & ADR —
channel-nostr플래그 및 기타 빌드 옵션. - 시크릿, 페어링 & 기기 인증 — 채널 자격증명을 저장 시 암호화하기.
- 설정: 채널, 도구 & 통합 — 전체
[channels_config]레퍼런스. - 온보딩 마법사 (revka onboard) — 채널을 대화식으로 설정하기.