Files
AriWeb-Suite/modules/arimail/docs/USAGE-API.md

9.0 KiB

메일 사용량 정보 제공 API (1.0.9)

웹메이커(WebHosting_AI_agent) 같은 외부 관리 시스템이 AriMail 의 디스크 사용량·메일 수·발송량을 도메인·계정 단위로 읽어 통합 관리할 수 있게 하는 읽기 전용 API 입니다. 구현은 server/usage.mjs.

1. 켜기 — 키 만들기

  1. 전체 설정 화면(기본 도메인의 전용 포트 https://<PUBLIC_HOST>:8791/?token=…, 또는 관리자 페이지 › 메일 서비스 설정 /setup)의 사용량 API 카드에서 키 만들기를 누릅니다.
  2. 키(au_…, 32바이트 난수)는 그때 한 번만 보입니다. 웹메이커의 설정에 복사해 두세요. 설정 화면에는 이후 앞뒤 일부만 보입니다.
  3. (권장) 같은 카드의 접속 허용 IP 에 웹메이커 서버의 IP 또는 CIDR 을 적고 저장합니다(쉼표 구분, 예 203.0.113.10, 10.0.0.0/8). 비우면 키만 맞으면 어디서나 허용합니다.
  4. 키를 바꾸려면 키 다시 만들기(기존 키는 즉시 무효), 끄려면 키 삭제. 키는 기본 도메인의 설정 파일(data/config.json 의 USAGE_API_KEY)에만 저장되고 서버 하나에 하나입니다(모든 도메인을 한 키로 봄).

API 로도 할 수 있습니다(전용 포트의 토큰 또는 관리자 세션): POST /api/setup/usage-key {"action":"generate"} → { ok, key, endpoint }, {"action":"revoke"} → { ok, enabled:false }. 허용 IP 는 PUT /api/setup/config {"values":{"USAGE_API_ALLOW":"…"}}.

2. 부르기

GET https://<기본 도메인 호스트>/api/usage                 모든 도메인 요약
GET https://<기본 도메인 호스트>/api/usage/<도메인>        도메인 하나 상세(계정 목록·일별 추이 포함)
헤더: Authorization: Bearer <키>       (또는 X-Usage-Key: <키>)
쿼리: days=30     일별 추이·계정별 기간 합계의 기간(1~366, 기본 30)
      accounts=1  계정 목록 포함(요약은 기본 0, 상세는 기본 1)
      series=1    일별 추이 포함(요약은 기본 0, 상세는 기본 1)

어느 등록 호스트로 불러도 같습니다(예 https://webmail.ariweb.net/api/usage). 경로 접두사 아래의 도메인(site.example.com/mail)은 https://site.example.com/mail/api/usage.

curl -s -H 'Authorization: Bearer au_…' 'https://mail.arihakdang.com/api/usage?days=30' | jq .totals
curl -s -H 'Authorization: Bearer au_…' 'https://mail.arihakdang.com/api/usage/ariweb.net?days=7'

3. 응답

전체 요약(/api/usage):

{ "ok": true, "version": "1.0.9", "generatedAt": "…", "primary": "arihakdang.com",
  "totals": { "domains": 2, "accounts": 5, "storageBytes": 12345678, "largeFileBytes": 0, "messages": 420, "sentMonth": 31, "receivedMonth": 88 },
  "domains": [ { …도메인 보고서(아래, accountList·daily 없음)… } ] }

도메인 보고서(/api/usage/<도메인> 또는 domains[] 의 항목):

필드 뜻
domain, primary, enabled, hosts, authMode(local/www/webmaker), mailbox, inbound, outbound, timezone 도메인 정보. enabled:false 는 중지한 도메인
accounts { local, external, total, limit, percent, externalSource } — 게이트웨이 계정 수, 외부(웹메이커) 계정 수, 합계, 시스템 제한(0 = 없음)
storage { bytes, limit, percent, largeFiles:{count, bytes, sent} } — 모든 메일함의 사용량(MIME 기준 원본 크기 합), 시스템 제한, 대용량 첨부파일(별도 저장)
messages { total, inbound, outbound, drafts, failed } — 저장된 메일 수(휴지통 포함, 영구 삭제 제외)
traffic { day, week, month } 각각 { sent, received, total, sentBytes, receivedBytes, start, end } — 통계 시간대(STATS_TIMEZONE, 기본 Asia/Seoul) 기준 오늘·이번 주(월~일)·이달. monthlyLimit, monthlyPercent 는 월간 통수 제한 대비
period { days, start, end } — 아래 daily·계정별 기간 합계의 범위(daily 또는 accountList 를 포함할 때만 있음)
daily[] { date:"YYYY-MM-DD", sent, received, sentBytes, receivedBytes } 오래된 날부터 days 개
accountList[] { login, name, mailbox, role, source, status, messages, bytes, limit, percent, lastLoginAt, sent, received, sentBytes, receivedBytes } — 계정(메일함)마다. source 는 local(게이트웨이 계정) / www(연결된 웹 서비스 관리자) / webmaker(웹메이커 계정) / orphan(계정은 지웠지만 메일이 남은 메일함). sent·received·*Bytes 는 period 안의 합계, bytes·limit 은 현재 사용량과 적용 중인 최대 크기(0 = 없음)
limits { system, admin } — 설치 시 시스템 제한(LIMIT_*)과 관리자 페이지의 제한 값(안내용)

"발신" 은 발송이 끝난 메일(state='sent', 발송 시각 기준), "수신" 은 받은 시각 기준입니다. 바이트는 저장된 원본(.eml) 크기라 MIME 변환으로 늘어난 실제 크기입니다. 메일 본문·주소록·비밀번호·API 키는 어떤 응답에도 들어가지 않습니다.

오류: usage_api_disabled(404, 키를 만들지 않음) · unauthenticated(401) · forbidden_ip(403) · rate_limited(429) · domain_not_found(404) · method_not_allowed(405). 모든 응답은 Cache-Control: no-store. 전체 요약에서 어느 도메인의 조회가 실패하면 그 항목만 { domain, error:'server_error' } 로 표시되고 합계에서 빠집니다. accounts.externalSource.error 에는 웹메이커 파일을 읽지 못한 사유(파일 경로 포함)가 그대로 들어갑니다.

4. 보안 대책 — 웹메이커의 해당 기능에서만 접근

장치 내용
비밀 키 32바이트 난수(au_…). 전체 설정 화면에서만 만들고 한 번만 표시, 비교는 상수 시간. 키가 없으면 API 자체가 404
접속 IP 제한 USAGE_API_ALLOW(IP/CIDR 목록)에 웹메이커 서버만 적어 두면 키가 유출돼도 다른 곳에서는 403. 접속 IP 는 클라이언트가 넣을 수 있는 헤더가 아니라 nginx 가 보증하는 값 — X-Real-IP(1.0.9 템플릿) 또는 X-Forwarded-For 의 마지막 주소(nginx 가 덧붙인 실제 접속 주소) — 로 정합니다. Cloudflare 프록시 뒤라면 실제 접속 주소가 Cloudflare 이므로 환경 변수 USAGE_TRUST_CF=1 을 두어 CF-Connecting-IP 를 믿게 하거나(원본 서버 접근을 Cloudflare IP 로 제한한 경우만) IP 제한 대신 키만 쓰세요. 저장 때 항목 형식을 검사해 오타가 있으면 422 로 거부합니다
시도 제한 키가 틀린 요청 IP 마다 15분 10회(그 뒤 429), 성공 요청도 IP 마다 1분 120회
읽기 전용·최소 정보 GET 만, 수(통·바이트)·제한·계정 이름만. 쓰기 동작 없음. 세션 쿠키와 무관(쿠키로는 못 부름)
기록 성공 호출은 감사 기록(audit_log, actor usage-api), 거부(틀린 키·허용 밖 IP·빈도 초과)는 서버 로그에 IP·사유와 함께 남음
키를 만들 수 있는 사람 전체 설정 화면(전용 포트 토큰) 또는 기본 도메인 관리자 세션. 기본 도메인 관리자는 모든 도메인의 계정 목록·사용량을 볼 수 있는 키를 만들 수 있으므로 운영자만 두세요
전송 HTTPS(nginx) 로만 노출. 키 교체·삭제는 즉시 적용(재시작 없음)

웹메이커 쪽에는 키를 비밀 보관소(lib/vault.js, 예: 종류 arimail-usage)에 두고 서버 간 호출에만 쓰세요(브라우저에 내려보내지 않음).

5. 웹메이커에서 쓰는 예(Node, lib/connectors/arimail.js 에 더할 수 있는 모양)

// 설정: mail.url(= AriMail 공개 주소), 보관소 'arimail-usage' 에 키
async function usage(domain = '', { days = 30 } = {}) {
  const base = String(config.get('mail.url') || '').replace(/\/+$/, '');
  const key = vault.get('arimail-usage'); if (!base || !key) throw new Error('AriMail 사용량 API 주소/키 없음');
  const r = await fetch(`${base}/api/usage${domain ? '/' + encodeURIComponent(domain) : ''}?days=${days}`, { headers: { Authorization: 'Bearer ' + key }, signal: AbortSignal.timeout(20000) });
  const d = await r.json().catch(() => ({}));
  if (!r.ok) throw new Error(`AriMail 사용량 API ${r.status} ${d.error || ''}`);
  return d;   // 전체: d.totals / d.domains[]   도메인 하나: d.storage / d.traffic / d.accountList …
}
// 예: 사이트(site.ariweb.net)의 디스크 사용량과 이달 발송량
const u = await usage('site.ariweb.net', { days: 30 });
console.log(u.storage.bytes, u.traffic.month.sent, u.accountList.map((a) => [a.mailbox, a.bytes, a.sent]));

웹메이커의 관리자 콘솔 › 메일 시스템 화면에서 도메인마다 storage.bytes(디스크), traffic.month.sent(이달 발송), accounts.total(계정 수)을 보여 주고, 사용자(사이트 관리자) 화면에는 accountList 에서 그 사용자의 mailbox 행만 골라 보여 주면 됩니다. 1분에 120회 제한이 있으므로 화면마다 호출하지 말고 1~5분 캐시를 두는 편이 좋습니다.