Created
August 22, 2025 21:12
-
-
Save rksm/737b167d43b6fdd36126acebe9efc7d2 to your computer and use it in GitHub Desktop.
Revisions
-
rksm created this gist
Aug 22, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,238 @@ // ==UserScript== // @name Navigator Permissions Debug Logger // @namespace http://tampermonkey.net/ // @version 1.0 // @description Debug navigator.permissions.query and navigator.mediaDevices.getUserMedia calls // @author You // @match http://localhost:*/* // @match https://localhost:*/* // @match http://127.0.0.1:*/* // @match https://127.0.0.1:*/* // @match https://*.hyper.video/* // @match https://latest.dev.hyper.video/* // @match https://hyper-lite.dev/* // @grant GM_log // @run-at document-start // ==/UserScript== ;(function () { 'use strict' let callSequence = 0 const logPrefix = '[Navigator Debug]' const logStyle = 'color: #007ACC; font-weight: bold;' // Store original functions const originalPermissionsQuery = navigator.permissions?.query?.bind( navigator.permissions ) const originalGetUserMedia = navigator.mediaDevices?.getUserMedia?.bind( navigator.mediaDevices ) function formatTimestamp() { const now = new Date() return `${now.toISOString().split('T')[1]}` } function getCallStack() { const stack = new Error().stack // Remove the first few lines which are from this wrapper const lines = stack.split('\n').slice(3, 8) return lines.join('\n') } // Wrap navigator.permissions.query if (navigator.permissions && navigator.permissions.query) { navigator.permissions.query = async function (permissionDesc) { const sequence = ++callSequence const timestamp = formatTimestamp() console.group( `%c${logPrefix} [${sequence}] permissions.query CALLED @ ${timestamp}`, logStyle ) console.log('Permission:', permissionDesc) console.log('Call Stack:\n', getCallStack()) console.groupEnd() try { const result = await originalPermissionsQuery(permissionDesc) console.group( `%c${logPrefix} [${sequence}] permissions.query RESOLVED @ ${formatTimestamp()}`, 'color: #28a745; font-weight: bold;' ) console.log('Permission:', permissionDesc) console.log('State:', result.state) console.log('Full Result:', result) console.groupEnd() return result } catch (error) { console.group( `%c${logPrefix} [${sequence}] permissions.query REJECTED @ ${formatTimestamp()}`, 'color: #dc3545; font-weight: bold;' ) console.log('Permission:', permissionDesc) console.error('Error:', error) console.groupEnd() throw error } } } // Wrap navigator.mediaDevices.getUserMedia if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.mediaDevices.getUserMedia = async function (constraints) { const sequence = ++callSequence const timestamp = formatTimestamp() console.group( `%c${logPrefix} [${sequence}] getUserMedia CALLED @ ${timestamp}`, logStyle ) console.log('Constraints:', JSON.parse(JSON.stringify(constraints || {}))) console.log('Call Stack:\n', getCallStack()) console.groupEnd() try { const stream = await originalGetUserMedia(constraints) const audioTracks = stream.getAudioTracks().map(t => ({ id: t.id, label: t.label, kind: t.kind, enabled: t.enabled, muted: t.muted, readyState: t.readyState, settings: t.getSettings ? t.getSettings() : {}, })) const videoTracks = stream.getVideoTracks().map(t => ({ id: t.id, label: t.label, kind: t.kind, enabled: t.enabled, muted: t.muted, readyState: t.readyState, settings: t.getSettings ? t.getSettings() : {}, })) console.group( `%c${logPrefix} [${sequence}] getUserMedia RESOLVED @ ${formatTimestamp()}`, 'color: #28a745; font-weight: bold;' ) console.log( 'Constraints:', JSON.parse(JSON.stringify(constraints || {})) ) console.log('Stream ID:', stream.id) console.log('Audio Tracks:', audioTracks) console.log('Video Tracks:', videoTracks) console.groupEnd() return stream } catch (error) { console.group( `%c${logPrefix} [${sequence}] getUserMedia REJECTED @ ${formatTimestamp()}`, 'color: #dc3545; font-weight: bold;' ) console.log( 'Constraints:', JSON.parse(JSON.stringify(constraints || {})) ) console.error('Error:', { name: error.name, message: error.message, constraintName: error.constraintName || null, }) console.groupEnd() throw error } } } // Also wrap enumerateDevices for completeness if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) { const originalEnumerateDevices = navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices) navigator.mediaDevices.enumerateDevices = async function () { const sequence = ++callSequence const timestamp = formatTimestamp() console.group( `%c${logPrefix} [${sequence}] enumerateDevices CALLED @ ${timestamp}`, logStyle ) console.log('Call Stack:\n', getCallStack()) console.groupEnd() try { const devices = await originalEnumerateDevices() const deviceSummary = devices.map(d => ({ kind: d.kind, label: d.label || '(no label)', deviceId: d.deviceId ? `${d.deviceId.substring(0, 8)}...` : '(no id)', groupId: d.groupId ? `${d.groupId.substring(0, 8)}...` : '(no group)', })) console.group( `%c${logPrefix} [${sequence}] enumerateDevices RESOLVED @ ${formatTimestamp()}`, 'color: #28a745; font-weight: bold;' ) console.table(deviceSummary) console.groupEnd() return devices } catch (error) { console.group( `%c${logPrefix} [${sequence}] enumerateDevices REJECTED @ ${formatTimestamp()}`, 'color: #dc3545; font-weight: bold;' ) console.error('Error:', error) console.groupEnd() throw error } } } console.log( `%c${logPrefix} Script loaded! Monitoring navigator.permissions.query and navigator.mediaDevices.getUserMedia`, 'color: #6f42c1; font-weight: bold;' ) // Add a global function to check status window.navigatorDebugStatus = function () { console.log(`%c${logPrefix} Status:`, 'color: #6f42c1; font-weight: bold;') console.log(`- Total calls intercepted: ${callSequence}`) console.log('- Wrapped APIs:') console.log( ' • navigator.permissions.query:', !!navigator.permissions?.query ) console.log( ' • navigator.mediaDevices.getUserMedia:', !!navigator.mediaDevices?.getUserMedia ) console.log( ' • navigator.mediaDevices.enumerateDevices:', !!navigator.mediaDevices?.enumerateDevices ) } // Add helper to reset counter window.navigatorDebugReset = function () { callSequence = 0 console.log( `%c${logPrefix} Call sequence counter reset`, 'color: #6f42c1; font-weight: bold;' ) } console.log(`%c${logPrefix} Helper functions available:`, 'color: #6f42c1;') console.log(' - window.navigatorDebugStatus() : Check wrapper status') console.log(' - window.navigatorDebugReset() : Reset call counter') })()