#!/usr/bin/env python import re import pyperclip # pip install pyperclip def redact_github_tokens(text): # Patterns for GitHub tokens (Personal Access Tokens, fine-tuned tokens, etc.) # Example formats: # - ghp_xxx... (Personal Access Token) # - github_pat_xxx... (Fine-grained) # - gho_xxx..., ghs_xxx..., ghr_xxx..., etc. token_patterns = [ r'(gh[pousr]_[A-Za-z0-9]{30,})', r'(github_pat_[A-Za-z0-9_]{22,255})' ] # Combine all patterns combined_pattern = '|'.join(token_patterns) regex = re.compile(combined_pattern) def mask_token(match): token = match.group(0) underscore_indices = [i for i, c in enumerate(token) if c == '_'] if len(underscore_indices) >= 3: prefix_end = underscore_indices[1] + 1 # preserve up to second underscore elif len(underscore_indices) == 1: prefix_end = 4 # preserve first 4 characters else: # default behavior: preserve up to last underscore prefix_end = token.rfind('_') + 1 if '_' in token else 4 suffix_length = 8 if len(token) <= prefix_end + suffix_length: return token # too short to mask prefix = token[:prefix_end] suffix = token[-suffix_length:] masked_length = len(token) - len(prefix) - len(suffix) return prefix + '*' * masked_length + suffix # Substitute tokens with redacted version return regex.sub(mask_token, text) def main(): clipboard_content = pyperclip.paste() redacted_content = redact_github_tokens(clipboard_content) pyperclip.copy(redacted_content) print("Clipboard content scanned and redacted (if any GitHub tokens were found).") if __name__ == "__main__": main()