DEV Community

Cover image for Maigret: 고장나지 않는 OSINT 스캐너란 무엇인가
Rihpig
Rihpig

Posted on • Originally published at apidog.com

Maigret: 고장나지 않는 OSINT 스캐너란 무엇인가

대부분의 OSINT 도구는 빠르게 노후화됩니다. 웹 환경이 바뀌고, 사이트 엔드포인트가 이동하며, 캡차가 강화되면 많은 도구가 1~2년 안에 쓸모없어집니다. Maigret은 예외에 가깝습니다. 수년간 유지 관리되어 왔고, 3,000개 이상의 사이트를 지원하며, Python 패키지, Telegram 봇, 웹 UI를 제공합니다. 더 중요한 점은 사이트가 계속 변해도 스캐너를 오래 유지하는 엔지니어링 패턴을 잘 보여준다는 것입니다.

지금 Apidog 사용해 보기

이 글은 단순한 조회 방법이 아니라 엔지니어 관점의 구현 가이드입니다. Maigret이 무엇을 하는지, 합법적인 연구 및 보안 사용 사례는 무엇인지, 수천 개 사이트로 확장할 수 있게 만든 아키텍처는 무엇인지, 그리고 Maigret의 테스트 패턴인 시그니처 데이터베이스, 드리프트 감지, 재귀적 검증을 Apidog 기반 API 테스트에 어떻게 적용할 수 있는지 살펴봅니다.

아직 읽지 않으셨다면, 2026년 Postman 없이 API 테스트하기 글도 함께 참고하세요. API 테스트에서 패턴 매칭과 드리프트 감지를 어떻게 다룰 수 있는지 더 익숙한 맥락에서 설명합니다.

요약 (TL;DR)

  • Maigret은 사용자 이름을 입력받아 3,000개 이상의 사이트에서 공개 계정 존재 여부와 공개 프로필 정보를 확인합니다.
  • 핵심은 코드가 아니라 데이터입니다. 사이트별 URL, 존재 문자열, 부재 문자열, 추출 규칙을 시그니처 데이터베이스로 관리합니다.
  • 합법적인 사용 사례에는 자기 계정 복구, 브랜드 남용 모니터링, 승인된 레드팀, 실종자 수색 지원, 탐사 저널리즘이 포함됩니다.
  • 동의 없이 개인을 추적하는 용도로 사용하면 괴롭힘 또는 스토킹에 해당할 수 있습니다.
  • Maigret의 아키텍처는 API 테스트에도 그대로 적용됩니다. 엔드포인트별 시그니처, 다중 신호 어설션, 주기적 재생, 드리프트 감지를 설계할 수 있습니다.
  • Apidog를 사용하면 이러한 패턴을 API 계약 테스트와 모니터링 워크플로에 적용할 수 있습니다.

Maigret의 정의와 아닌 것

Maigret은 soxoj가 유지 관리하는 MIT 라이선스 Python 도구입니다. 핵심 기능은 간단합니다.

pip install maigret
maigret username
Enter fullscreen mode Exit fullscreen mode

사용자 이름을 입력하면 Maigret은 데이터베이스에 등록된 사이트들을 조회하고, 공개적으로 접근 가능한 프로필 정보를 수집한 뒤 보고서를 생성합니다.

명확히 구분해야 할 점이 있습니다.

  1. Maigret은 공개 데이터만 사용합니다.

    로그인, 탈취한 자격 증명, 비공개 API 키를 사용하지 않습니다. 익명 방문자에게 공개된 프로필만 읽습니다.

  2. 합법적인 연구 맥락에서 사용됩니다.

    조사 언론, 사기 방지, 브랜드 보호, 승인된 레드팀, 실종자 수색 지원 등에서 공개 흔적을 확인하는 데 쓰입니다.

  3. 오용될 수 있습니다.

    동의 없이 개인을 추적하거나 데이터를 축적하는 용도로 사용하면 윤리적·법적 문제가 됩니다. 제3자에게 사용하기 전에는 반드시 관할권의 법률과 승인 범위를 확인해야 합니다.

이 글의 초점은 사람을 추적하는 워크플로가 아니라, Maigret이 오래 유지되는 스캐너를 구현한 방식과 그 패턴을 API 테스트에 적용하는 방법입니다.

사이트 시그니처 데이터베이스

Maigret의 가장 중요한 구현 아이디어는 사이트 시그니처 데이터베이스입니다.

각 사이트는 코드에 하드코딩되지 않고 JSON 데이터로 정의됩니다. 이 데이터는 스캐너가 다음을 판단하는 데 필요한 정보를 담습니다.

  • 이 사이트에 특정 사용자 이름이 존재하는가?
  • 계정이 존재할 때 페이지는 어떤 특징을 갖는가?
  • 계정이 없을 때 페이지는 어떤 특징을 갖는가?
  • 공개 프로필에서 어떤 필드를 추출할 수 있는가?
  • 속도 제한, 캡차, 특수 헤더가 필요한가?

API 테스트로 바꾸어 생각하면 다음과 같습니다.

Maigret API 테스트
사이트 URL 템플릿 엔드포인트 URL
존재 문자열 성공 응답의 필수 필드
부재 문자열 오류 응답의 식별 문자열
추출 규칙 응답 스키마 또는 JSONPath
사이트별 헤더 인증 헤더, 버전 헤더
드리프트 감지 계약 테스트 실패

예를 들어 API 엔드포인트 시그니처는 다음처럼 데이터로 표현할 수 있습니다.

{
  "name": "GetUserProfile",
  "method": "GET",
  "url": "/api/users/{id}",
  "expectedStatus": 200,
  "requiredJsonPaths": [
    "$.id",
    "$.email",
    "$.createdAt"
  ],
  "forbiddenJsonPaths": [
    "$.error",
    "$.stack"
  ],
  "requiredHeaders": [
    "content-type"
  ]
}
Enter fullscreen mode Exit fullscreen mode

이 방식의 장점은 분명합니다. 테스트 로직은 공통화하고, 엔드포인트별 기대값은 데이터로 관리할 수 있습니다. 공급업체나 내부 서비스가 늘어나도 테스트 러너를 다시 작성할 필요가 없습니다.

같은 접근은 계약 우선 API 개발MCP 서버 테스트 플레이북에서도 중요하게 다룬 패턴입니다.

Maigret이 “발견”과 “미발견”을 판단하는 방식

단순한 스캐너라면 다음처럼 구현할 수 있습니다.

import requests

url = "https://example.com/user/alice"
res = requests.get(url)

if res.status_code == 200:
    print("found")
else:
    print("not found")
Enter fullscreen mode Exit fullscreen mode

하지만 실제 웹에서는 이 방식이 거의 안정적으로 동작하지 않습니다.

많은 사이트는 존재하지 않는 사용자에게도 200 OK를 반환합니다. 어떤 사이트는 홈페이지를 반환하고, 어떤 사이트는 “사용자를 찾을 수 없음” 페이지를 200으로 반환하며, 어떤 사이트는 캡차 페이지를 반환합니다.

Maigret은 상태 코드 하나에 의존하지 않고 여러 신호를 조합합니다.

  • urlMain, url 템플릿
  • presenseStrs: 사용자가 존재할 때 나타나야 하는 문자열
  • absenceStrs: 사용자가 없을 때 나타나는 문자열
  • 사용자 이름 또는 프로필 필드 추출용 정규식
  • 사이트별 헤더
  • 카테고리 및 국가 태그

판단 로직은 다음과 비슷합니다.

def detect(response_text, presence_strs, absence_strs):
    has_presence = all(s in response_text for s in presence_strs)
    has_absence = any(s in response_text for s in absence_strs)

    if has_presence and not has_absence:
        return "found"

    if has_absence:
        return "not_found"

    return "unknown"
Enter fullscreen mode Exit fullscreen mode

API 테스트에서도 동일한 원칙이 필요합니다.

나쁜 테스트:

pm.test("status is 200", function () {
  pm.response.to.have.status(200);
});
Enter fullscreen mode Exit fullscreen mode

더 나은 테스트:

pm.test("user profile response is valid", function () {
  pm.response.to.have.status(200);

  const json = pm.response.json();

  pm.expect(json).to.have.property("id");
  pm.expect(json).to.have.property("email");
  pm.expect(json).to.have.property("createdAt");
  pm.expect(json).to.not.have.property("error");
});
Enter fullscreen mode Exit fullscreen mode

200 OK만 확인하면 캐시된 응답, 빈 응답, 일반 오류 페이지를 놓칠 수 있습니다. Apidog에서도 상태 코드, 헤더, 본문 필드, JSONPath 기반 검증을 함께 구성하는 방식이 더 안전합니다.

재귀적 검색과 정보 추출

Maigret은 계정을 찾은 뒤 단순히 “있음”으로 끝내지 않습니다.

공개 프로필 페이지에서 다음과 같은 추가 식별자를 추출할 수 있습니다.

  • 연결된 이메일 주소
  • 공개 전화번호
  • 실명
  • 다른 사용자 이름
  • 외부 프로필 링크

그다음 새로 발견한 식별자를 다시 검색 루프에 넣습니다. 즉, 하나의 사용자 이름에서 다른 사용자 이름, 다른 사이트, 다른 공개 프로필로 확장됩니다.

이 패턴을 API 테스트에 적용하면 다음과 같습니다.

  1. /users/{id} 응답을 호출합니다.
  2. 응답에서 organizationId를 추출합니다.
  3. /organizations/{organizationId}를 호출합니다.
  4. 응답에서 billingAccountId를 추출합니다.
  5. /billing/accounts/{billingAccountId} 계약을 검증합니다.

예시:

// Step 1: user response에서 organizationId 저장
const user = response.json();
client.global.set("organizationId", user.organizationId);
Enter fullscreen mode Exit fullscreen mode
GET /organizations/{{organizationId}}
Enter fullscreen mode Exit fullscreen mode

이 방식은 단일 엔드포인트 테스트보다 실제 시스템 흐름에 가깝습니다. 한 응답에서 발견한 필드를 다음 테스트의 입력으로 사용하면, 문서화되지 않은 의존성이나 누락된 계약을 더 빨리 찾을 수 있습니다.

캡차와 속도 제한 처리

Maigret은 자동화 방지 장치를 무력화하려는 도구가 아닙니다. 대신 응답 형태를 읽고 제한 상황을 감지합니다.

일반적인 대응 전략은 다음과 같습니다.

  • 사용자 에이전트 조정
  • 사이트별 재시도 헤더 준수
  • 모바일 또는 간소화된 도메인 사용
  • 허용되는 경우 Tor 또는 I2P 라우팅
  • 캡차가 감지되면 자동 판단을 중단하고 수동 확인으로 넘김

핵심은 “우회”가 아니라 감지 후 후퇴입니다.

API 클라이언트와 테스트 러너도 같은 태도를 가져야 합니다. 429 Too Many Requests를 받았는데 계속 요청을 밀어 넣으면 테스트가 아니라 공격처럼 보일 수 있습니다.

예시 처리:

if (response.status === 429) {
  const retryAfter = response.headers.get("Retry-After");

  throw new Error(
    `Rate limited. Retry after: ${retryAfter || "unknown"} seconds`
  );
}
Enter fullscreen mode Exit fullscreen mode

CI에서 API 테스트를 실행할 때도 다음을 설정하는 것이 좋습니다.

  • 테스트 환경별 요청 속도 제한
  • 재시도 횟수 상한
  • Retry-After 헤더 준수
  • 실패 시 무한 재시도 금지
  • 프로덕션 API에 대한 쓰기 테스트 제한

Maigret이 사이트의 제한을 신호로 다루는 것처럼, API 테스트도 제한 응답을 정상적인 테스트 입력으로 다뤄야 합니다.

시그니처 드리프트 문제

3,000개 이상의 사이트 시그니처는 지속적으로 변합니다.

사이트가 다음을 변경하면 기존 시그니처는 깨집니다.

  • 프로필 URL 패턴
  • HTML 구조
  • 오류 메시지
  • 리디렉션 정책
  • 캡차 정책
  • 브랜드 또는 도메인

이 문제를 Maigret은 세 가지 방식으로 완화합니다.

  • 중앙 GitHub 리포지토리에서 시그니처 자동 업데이트
  • 커뮤니티 풀 리퀘스트를 통한 사이트별 수정
  • --update 플래그를 통한 수동 업데이트
  • 알려진 기존 사용자 이름에 대한 테스트 하네스

특히 중요한 부분은 알려진 정상값으로 시그니처를 검증한다는 점입니다. 각 사이트에 대해 실제로 존재하는 테스트용 사용자 이름을 두고, 해당 시그니처가 여전히 “발견”을 반환하는지 확인합니다.

API 테스트에서도 같은 구조가 필요합니다.

예를 들어 결제 API의 정상 응답 픽스처를 저장해 둡니다.

{
  "id": "pay_123",
  "status": "succeeded",
  "amount": 4900,
  "currency": "USD"
}
Enter fullscreen mode Exit fullscreen mode

그리고 주기적으로 라이브 또는 스테이징 엔드포인트를 호출해 다음을 비교합니다.

  • 상태 코드가 그대로인가?
  • 필수 필드가 사라지지 않았는가?
  • 타입이 바뀌지 않았는가?
  • 오류 응답 구조가 변경되지 않았는가?
  • 새 필드가 추가되었는가?

Apidog에서는 엔드포인트별 테스트를 저장하고, 반복 실행하고, 응답 차이를 확인하는 방식으로 이 패턴을 구현할 수 있습니다. 특정 공급업체 API의 수동 검증 흐름은 DeepSeek V4 API 가이드에서도 참고할 수 있습니다.

선택적 AI 요약 모드

Maigret의 --ai 플래그는 원시 결과를 OpenAI 호환 LLM 엔드포인트로 보내 짧은 조사 요약을 생성합니다. API 키는 사용자가 직접 제공합니다.

중요한 점은 LLM이 판정을 내리지 않는다는 것입니다.

  • 계정 존재 여부 판단: 규칙 기반
  • 문자열 매칭: 규칙 기반
  • 필드 추출: 규칙 기반
  • 최종 요약: LLM 후처리

이 구조가 안전합니다. LLM은 결과를 읽기 쉽게 정리하지만, 테스트의 통과/실패를 결정하지 않습니다.

API 모니터링에서도 같은 구조를 권장합니다.

API 실행 결과
   ↓
규칙 기반 어설션
   ↓
통과 / 실패 결정
   ↓
LLM 요약
   ↓
Slack 또는 이슈 트래커로 전달
Enter fullscreen mode Exit fullscreen mode

LLM을 판정자로 쓰면 환각과 비결정성이 테스트 안정성을 해칠 수 있습니다. 반대로 확정적 테스트 결과를 요약하는 후처리기로 쓰면 유용합니다. 이 원칙은 컴퓨터 사용 대 구조화된 API 글에서도 다룬 구조화 우선 접근과 맞닿아 있습니다.

합법적인 사용 사례

Maigret을 사용할 수 있는 대표적인 합법적 상황은 다음과 같습니다.

1. 자기 계정 복구

오래전에 사용한 사용자 이름으로 가입했던 계정을 찾을 수 있습니다. 개인정보 정리, 계정 삭제, 디지털 발자국 감사에 유용합니다.

2. 브랜드 남용 모니터링

기업은 자사 브랜드명, 제품명, 임원 이름 등을 기준으로 사칭 계정을 확인할 수 있습니다. 이 경우에도 내부 정책과 법무 검토를 거치는 것이 좋습니다.

3. 실종자 수색 지원

가족 동의와 관련 기관 협조가 있는 상황에서 공개 디지털 흔적을 확인하는 데 사용할 수 있습니다. 독자적으로 행동하면 수사를 방해할 수 있으므로 반드시 공식 절차와 협력해야 합니다.

4. 승인된 레드팀

계약 범위가 명확한 침투 테스트에서 조직의 공개 공격 표면을 파악하는 데 사용할 수 있습니다. 도구가 합법성을 만드는 것이 아니라, 계약과 승인 범위가 합법성을 만듭니다.

5. 탐사 저널리즘

사기, 공익 이슈, 조직 범죄 등을 조사하는 기자가 편집 및 법률 검토 아래 OSINT 도구를 사용할 수 있습니다.

반대로 다음은 적절하지 않습니다.

  • 호기심으로 낯선 사람 검색
  • 전 배우자 또는 지인 감시
  • 동의 없는 개인 데이터셋 구축
  • 괴롭힘, 협박, 신상털이 목적의 사용

Maigret에서 API 테스트에 적용할 수 있는 패턴

Maigret의 구조에서 API 테스트로 바로 가져올 수 있는 패턴은 다섯 가지입니다.

1. 수동 코드 대신 시그니처 데이터베이스 사용

엔드포인트별 기대 동작을 코드가 아니라 데이터로 정의합니다.

{
  "endpoint": "GET /v1/orders/{id}",
  "expectedStatus": 200,
  "requiredFields": [
    "id",
    "status",
    "total",
    "items"
  ],
  "forbiddenFields": [
    "debug",
    "stackTrace"
  ]
}
Enter fullscreen mode Exit fullscreen mode

이렇게 하면 테스트 러너는 그대로 두고 시그니처만 업데이트할 수 있습니다.

2. 다중 신호 어설션 사용

상태 코드만 보지 말고 다음을 함께 확인합니다.

  • 상태 코드
  • 응답 헤더
  • JSON 스키마
  • 필수 필드
  • 금지 필드
  • 오류 코드
  • 응답 시간

3. 시그니처 자동 동기화

팀이 여러 명이면 테스트 정의가 흩어지기 쉽습니다. 중앙 저장소 또는 클라우드 프로젝트로 동기화해야 합니다. Apidog 프로젝트 동기화는 이 목적에 맞습니다. 관련 워크플로는 Postman 없이 API 테스트하기에서 더 자세히 다뤘습니다.

4. 드리프트 감지 예약

주기적으로 테스트를 실행하고 결과를 비교합니다.

예시 CI 흐름:

name: API Contract Check

on:
  schedule:
    - cron: "0 */6 * * *"
  workflow_dispatch:

jobs:
  contract-test:
    runs-on: ubuntu-latest
    steps:
      - name: Run API contract tests
        run: |
          echo "Run Apidog or API test CLI here"
Enter fullscreen mode Exit fullscreen mode

목표는 사용자가 장애를 발견하기 전에 계약 변경을 감지하는 것입니다.

5. LLM은 판정자가 아니라 요약기로 사용

테스트 통과/실패는 규칙으로 결정합니다. LLM은 마지막에 실행 결과를 사람이 읽기 쉽게 요약하는 데만 사용합니다.

Maigret 실행 시 흔히 하는 실수

도구 자체를 실험할 때도 몇 가지 실수를 피해야 합니다.

-a 없이 실행하고 완전하다고 가정

기본 실행은 전체 사이트가 아니라 우선순위가 높은 일부 사이트를 대상으로 할 수 있습니다. 더 넓은 범위가 필요하면 전체 스캔 옵션을 확인해야 합니다.

maigret username -a
Enter fullscreen mode Exit fullscreen mode

전체 스캔은 시간이 더 오래 걸립니다.

태그 무시

국가나 카테고리별 사이트를 놓칠 수 있습니다. 특정 지역이나 서비스군이 중요하다면 태그 필터를 사용합니다.

maigret username --tags us,jp
Enter fullscreen mode Exit fullscreen mode

업데이트 생략

오래된 시그니처는 오탐과 누락을 만듭니다. 중요한 실행 전에는 업데이트를 확인합니다.

maigret --update
Enter fullscreen mode Exit fullscreen mode

Tor 차단을 잘못 해석

일부 사이트는 Tor 출구 노드를 차단합니다. 이것을 대상 사용자에 대한 신호로 해석하면 안 됩니다. 네트워크 조건과 사이트 정책의 결과일 수 있습니다.

추출된 필드를 증거로 단정

Maigret은 페이지에 노출된 문자열을 추출합니다. 페이지는 오래되었거나 조작되었거나 다른 사람의 정보를 포함할 수 있습니다. 결과는 증거가 아니라 단서로 다뤄야 합니다.

실제 사용 사례

보안 컨설팅 회사는 레드팀 범위 설정 단계에서 Maigret을 사용해 고객 조직의 공개 공격 표면을 확인할 수 있습니다. 결과는 초기 보고서에 포함되어 고객이 외부에 노출된 계정과 브랜드 사용 현황을 이해하는 데 도움을 줍니다.

사기 조사자는 --ai 플래그를 사용해 긴 스캔 결과를 비기술 고객이 읽을 수 있는 짧은 요약으로 바꿀 수 있습니다. 이때 데이터 수집과 판정은 규칙 기반이고, LLM은 읽기 쉬운 설명 계층입니다.

엔지니어링 팀은 같은 패턴을 내부 API 테스트에 적용할 수 있습니다. 예를 들어 200개의 마이크로서비스에 대해 엔드포인트 시그니처를 관리하고, 주기적으로 재생하고, 응답 형태가 바뀌면 알림을 보낼 수 있습니다. 이 구조는 Apidog 기반 API 계약 테스트와 잘 맞습니다.

결론

Maigret은 OSINT 도구이지만, 엔지니어링 관점에서는 오래 유지되는 테스트 시스템의 좋은 사례입니다. 핵심은 다음입니다.

  • 사이트별 동작을 코드가 아니라 시그니처 데이터로 관리합니다.
  • 상태 코드 하나가 아니라 여러 신호를 조합해 판단합니다.
  • 시그니처가 변할 수 있음을 전제로 업데이트와 검증 루프를 둡니다.
  • 알려진 정상값으로 드리프트를 조기에 감지합니다.
  • LLM은 판정자가 아니라 후처리 요약기로 사용합니다.

API 테스트에도 동일한 원칙을 적용할 수 있습니다. Apidog를 열고 프로젝트의 핵심 엔드포인트 하나를 골라 다음처럼 설계해 보세요.

  1. 필수 상태 코드를 정의합니다.
  2. 필수 응답 필드를 정의합니다.
  3. 없어야 하는 오류 필드를 정의합니다.
  4. 정상 응답 픽스처를 저장합니다.
  5. 주기적 재생을 설정합니다.
  6. 응답 형태가 바뀌면 알림을 받도록 구성합니다.

이 규율은 공급업체나 내부 팀이 새벽 2시에 필드 이름을 바꾸었을 때 가치를 발휘합니다. 사용자가 먼저 깨닫기 전에 테스트 스위트가 먼저 알려줘야 합니다.

FAQ

Maigret 사용은 합법적인가요?

관할권과 대상에 따라 다릅니다. 자신, 소유한 계정, 서면 승인을 받은 회사, 승인된 저널리즘 또는 계약 범위 내 보안 테스트에 사용하는 것은 일반적으로 허용될 수 있습니다. 동의 없는 개인을 대상으로 실행하면 EU, 미국, 영국 및 여러 지역에서 스토킹 또는 괴롭힘 법률에 저촉될 수 있습니다.

Maigret은 Python 없이 작동하나요?

공식 패키지는 Python 3.10+ 기반입니다. 로컬 설치가 어렵다면 Telegram 봇 또는 Cloud Shell 설정을 사용할 수 있습니다.

3,000개 사이트 지원은 정확한가요?

리포지토리의 사이트 데이터베이스에는 3,000개 이상의 항목이 있습니다. 다만 모든 사이트가 항상 정상 동작하는 것은 아닙니다. 사이트 구조 변경, 캡차, 차단 정책 때문에 일부 시그니처는 업데이트가 필요할 수 있습니다.

AI 모드는 무엇을 하나요?

--ai 플래그는 OpenAI 호환 LLM을 사용해 확정적 검색 결과를 읽기 쉬운 보고서로 요약합니다. 검색 판단 자체는 바꾸지 않습니다. API 키는 사용자가 직접 제공해야 합니다.

CI에서 Maigret을 사용해도 되나요?

OSINT 조사는 일반적으로 상호작용적이고 승인 범위가 중요한 작업이므로 CI에 무작정 넣는 것은 적절하지 않습니다. 다만 Maigret의 아키텍처 패턴인 시그니처 데이터베이스, 드리프트 감지, 예약된 재생은 API 테스트 CI 파이프라인에 적용하기 좋습니다. Apidog는 이런 API 테스트 흐름을 구성하는 데 사용할 수 있습니다.

Sherlock과는 어떻게 다른가요?

Sherlock은 더 오래되고 단순한 사용자 이름 검색 도구입니다. Maigret은 정보 추출, 재귀적 검색, 캡차 처리, AI 요약 모드, 더 풍부한 사이트 데이터베이스로 확장되었습니다. 둘 다 MIT 라이선스이며 OSINT 도구 아키텍처를 이해하는 데 참고할 만합니다.

오래된 시그니처는 어디에 보고하나요?

Maigret GitHub 리포지토리의 이슈 또는 풀 리퀘스트로 보고하면 됩니다. 오래된 사이트 하나당 하나의 PR로 수정하는 방식이 일반적이며, 커뮤니티 기여가 데이터베이스 품질을 유지하는 핵심입니다.

Top comments (0)