← back to projects

~/projects $ cat ghost-protocol

facial recognition anti-surveillance · repo · devpost
Most Secure Software Most Creative Use of Redis Cloud K-State 2023 · co-built with Delroy Wright and Dylan Kneidel

## live demo

This runs face-api.js directly in your browser. No server, no upload, no storage. The demo loads ~6 MB of TensorFlow.js model weights from a CDN once, then does detection and recognition on-device. Click register face while looking at the camera to add yourself to the whitelist — your face will get blurred. Anyone else who appears gets a red box and bumps the alert counter, exactly like the original.

Privacy: getUserMedia opens your camera locally. Face descriptors stay in JavaScript memory and are wiped when you close the tab. Nothing is sent anywhere. View source if you want to verify.
click start camera below.
faces in frame
0
whitelisted
0
unknown
0
alerts triggered
0

## what it was

An anti-surveillance tool with one inverted premise — most face-recognition systems exist to identify and track people. Ghost Protocol existed to protect the people it knew and surface the ones it didn't. Friendly faces (whitelist) got blurred on screen and in any recording. Hostile faces (blacklist) got a red box and triggered an SMTP alert to a list of execs with the camera's IP geolocation attached. Everything else got logged as Unknown.

The whitelist/blacklist lived in Redis Cloud so the desktop client could rebuild its in-memory face-encoding index every ~10 seconds without a restart. A Flask admin app on the side handled face capture and list management.

## architecture

webcam │ ▼ cv2.VideoCapture ──► resize 0.5x ──► face_recognition.face_encodings() │ ▼ compare against Redis lists whitelist ◄──┐ blacklist ◄──┐ │ │ │ │ ▼ │ ▼ │ blur ROIred box + label │ │ │ │ │ ▼ │ │ ALERT_FRAME_MAX (7) │ │ │ │ │ ▼ │ │ smtplib → execs │ │ + IP geolocation │ │ │ └────── Flask admin ─────┘ (add/remove faces)

## features

## code from the original

face_capture.py — match each detected face against Redis lists

# See if the face is a match for the known face(s)
matches = face_recognition.compare_faces(total_encodings, face_encoding)
face_distances = face_recognition.face_distance(total_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
    string_data = str(total_names[best_match_index])
    identified_names.append(string_data)
else:
    identified_names.append("Unknown")

face_capture.py — blur whitelisted faces in place

blur_kernel = np.ones((blur_amount, blur_amount), np.float32) / blur_amount**2
roi = frame[top:bottom, left:right]
roi = cv2.filter2D(src=roi, ddepth=-1, kernel=blur_kernel)
frame[top:bottom, left:right] = roi

send_emails.py — exec alert on confirmed blacklist hit

subject = f'BLACKLISTER in {city}'
body = location_details_string(location)
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.login(gmail_user, gmail_password)
for user in exec_emails:
    server.sendmail(gmail_user, user, email_text)

## retrospective

Hackathon code is hackathon code — credentials in creds.py, blocking SMTP on the main thread, no tests, the recognition tolerance hard-coded at 0.6 because that's what worked at 3am. But the core idea held up: facial recognition as defense rather than identification. The privilege-separation model (whitelist privileged, alert on unknown) is the right primitive for a lot of physical-security UI, and it's the one that keeps showing up in the work since.