140 lines
4.7 KiB
Python
140 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Tool to convert JSON cookies to the standard Netscape txt format.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
import logging
|
|
|
|
# Configure logging
|
|
logger = logging.getLogger('cookie_tool')
|
|
|
|
def convert_json_to_netscape(json_data):
|
|
"""
|
|
Converts a list of cookie dictionaries to a Netscape format string.
|
|
"""
|
|
netscape_cookies = []
|
|
# The header is optional but good practice for some tools.
|
|
netscape_cookies.append("# Netscape HTTP Cookie File")
|
|
netscape_cookies.append("# http://www.netscape.com/newsref/std/cookie_spec.html")
|
|
netscape_cookies.append("# This is a generated file! Do not edit.")
|
|
netscape_cookies.append("")
|
|
|
|
if not isinstance(json_data, list):
|
|
raise TypeError("Input JSON must be a list of cookie objects.")
|
|
|
|
for cookie in json_data:
|
|
if not isinstance(cookie, dict):
|
|
logger.warning(f"Skipping non-dictionary item in JSON list: {cookie}")
|
|
continue
|
|
|
|
domain = cookie.get('domain', '')
|
|
# The 'hostOnly' flag determines if the domain is accessible to subdomains.
|
|
# Netscape format's flag is TRUE if subdomains can access it.
|
|
# So, hostOnly=false means flag=TRUE.
|
|
# A leading dot in the domain also implies this for some implementations.
|
|
if domain.startswith('.'):
|
|
include_subdomains = 'TRUE'
|
|
else:
|
|
include_subdomains = 'FALSE' if cookie.get('hostOnly', True) else 'TRUE'
|
|
|
|
path = cookie.get('path', '/')
|
|
secure = 'TRUE' if cookie.get('secure', False) else 'FALSE'
|
|
|
|
# Expiration date. If session cookie or no expiration, use 0.
|
|
if cookie.get('session', False) or 'expirationDate' not in cookie or cookie['expirationDate'] is None:
|
|
expires = 0
|
|
else:
|
|
expires = int(cookie['expirationDate'])
|
|
|
|
name = cookie.get('name', '')
|
|
value = str(cookie.get('value', ''))
|
|
|
|
# Skip cookies without essential fields
|
|
if not domain or not name:
|
|
logger.warning(f"Skipping cookie with missing domain or name: {cookie}")
|
|
continue
|
|
|
|
netscape_cookies.append(
|
|
f"{domain}\t{include_subdomains}\t{path}\t{secure}\t{expires}\t{name}\t{value}"
|
|
)
|
|
|
|
return "\n".join(netscape_cookies)
|
|
|
|
def add_cookie_tool_parser(subparsers):
|
|
"""Add the parser for the 'convert-cookies' command."""
|
|
parser = subparsers.add_parser(
|
|
'convert-cookies',
|
|
description='Convert JSON cookies to Netscape format.',
|
|
formatter_class=argparse.RawTextHelpFormatter,
|
|
help='Convert JSON cookies to Netscape format.',
|
|
epilog="""
|
|
Reads a JSON array of cookie objects from stdin and prints the
|
|
Netscape cookie file format to stdout.
|
|
|
|
Example JSON input format (per cookie):
|
|
{
|
|
"domain": ".example.com",
|
|
"hostOnly": false,
|
|
"path": "/",
|
|
"secure": true,
|
|
"expirationDate": 1672531199,
|
|
"name": "my_cookie",
|
|
"value": "my_value"
|
|
}
|
|
|
|
Example usage:
|
|
cat cookies.json | yt-ops-client convert-cookies > cookies.txt
|
|
"""
|
|
)
|
|
parser.add_argument(
|
|
'input_file',
|
|
nargs='?',
|
|
type=argparse.FileType('r', encoding='utf-8'),
|
|
default=sys.stdin,
|
|
help="Path to the JSON cookie file. Reads from stdin if not provided."
|
|
)
|
|
parser.add_argument(
|
|
'-o', '--output',
|
|
type=argparse.FileType('w', encoding='utf-8'),
|
|
default=sys.stdout,
|
|
help="Output file path for the Netscape cookies. Defaults to stdout."
|
|
)
|
|
parser.add_argument('--verbose', action='store_true', help='Enable verbose logging.')
|
|
return parser
|
|
|
|
def main_cookie_tool(args):
|
|
"""Main logic for the 'convert-cookies' command."""
|
|
if args.verbose:
|
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s', stream=sys.stderr)
|
|
else:
|
|
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s', stream=sys.stderr)
|
|
|
|
try:
|
|
json_content = args.input_file.read()
|
|
if not json_content.strip():
|
|
logger.error("Input is empty.")
|
|
return 1
|
|
|
|
cookie_data = json.loads(json_content)
|
|
netscape_string = convert_json_to_netscape(cookie_data)
|
|
|
|
args.output.write(netscape_string + '\n')
|
|
|
|
if args.output is not sys.stdout:
|
|
logger.info(f"Successfully converted cookies to {args.output.name}")
|
|
|
|
return 0
|
|
except json.JSONDecodeError:
|
|
logger.error("Invalid JSON provided. Please check the input file.")
|
|
return 1
|
|
except TypeError as e:
|
|
logger.error(f"Error processing JSON: {e}")
|
|
return 1
|
|
except Exception as e:
|
|
logger.error(f"An unexpected error occurred: {e}", exc_info=args.verbose)
|
|
return 1
|