mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-29 18:46:59 +00:00
fix(desktop): allow camera capture through the permission handlers
The session permission hooks were written for the voice composer and denied
video outright, so any renderer getUserMedia({video}) failed with
NotAllowedError before the OS was ever consulted.
Rename isAudioCapturePermission to isMediaCapturePermission and accept video
alongside audio in both the request and check handlers. The OS capture
permission still applies, so the user keeps a real allow/deny.
This commit is contained in:
parent
585726ac2e
commit
47cb4ea1fe
1 changed files with 24 additions and 27 deletions
|
|
@ -5510,18 +5510,22 @@ function installContextMenu(window) {
|
|||
})
|
||||
}
|
||||
|
||||
// Microphone capture for the voice composer. The renderer drives mic access
|
||||
// Microphone and camera capture. The voice composer drives mic access and
|
||||
// renderer features (e.g. desktop plugins) can drive camera access, both
|
||||
// through getUserMedia, which Chromium gates behind these two session hooks.
|
||||
//
|
||||
// The naive `details.mediaTypes.includes('audio')` check works on macOS but
|
||||
// breaks on Windows: Chromium frequently fires the mic permission request with
|
||||
// an empty/undefined `mediaTypes`, so the strict check denies it and
|
||||
// getUserMedia throws NotAllowedError ("Microphone permission was denied").
|
||||
// We therefore treat an audio-capture request as allowed whenever it's the
|
||||
// 'media'/'audioCapture' permission AND mediaTypes either includes 'audio' OR
|
||||
// is empty/absent (the Windows case). Video is still denied.
|
||||
function isAudioCapturePermission(permission, details) {
|
||||
if (permission === 'audioCapture') {
|
||||
// breaks on Windows: Chromium frequently fires the request with an empty or
|
||||
// undefined `mediaTypes`, so a strict check denies it and getUserMedia throws
|
||||
// NotAllowedError. We therefore allow the capture permissions and treat absent
|
||||
// metadata as allowed.
|
||||
//
|
||||
// Granting here is not the last gate: the OS still applies its own capture
|
||||
// permission (macOS TCC prompts on first use, per the NSMicrophone/NSCamera
|
||||
// usage strings), so the user keeps a real allow/deny and can revoke it in
|
||||
// System Settings afterwards.
|
||||
function isMediaCapturePermission(permission, details) {
|
||||
if (permission === 'audioCapture' || permission === 'videoCapture') {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -5531,38 +5535,31 @@ function isAudioCapturePermission(permission, details) {
|
|||
|
||||
const mediaTypes = details?.mediaTypes
|
||||
|
||||
// Windows: mediaTypes is often empty for a capture request. Don't deny on
|
||||
// missing metadata.
|
||||
if (!Array.isArray(mediaTypes) || mediaTypes.length === 0) {
|
||||
// Windows: mediaTypes is often empty for a mic request. Don't deny on
|
||||
// missing metadata. (A video request would carry mediaTypes:['video'].)
|
||||
return true
|
||||
}
|
||||
|
||||
return mediaTypes.includes('audio') && !mediaTypes.includes('video')
|
||||
return mediaTypes.includes('audio') || mediaTypes.includes('video')
|
||||
}
|
||||
|
||||
function installMediaPermissions() {
|
||||
// Async request handler: the prompt-style path (most platforms).
|
||||
session.defaultSession.setPermissionRequestHandler((_webContents, permission, callback, details) => {
|
||||
callback(isAudioCapturePermission(permission, details))
|
||||
callback(isMediaCapturePermission(permission, details))
|
||||
})
|
||||
|
||||
// Synchronous check handler: Chromium consults this for getUserMedia on
|
||||
// Windows in addition to (or instead of) the request handler. Without it,
|
||||
// the check defaults to false and the mic is denied before the request
|
||||
// the check defaults to false and capture is denied before the request
|
||||
// handler ever runs.
|
||||
session.defaultSession.setPermissionCheckHandler((_webContents, permission, _origin, details) => {
|
||||
if (permission === 'media' || permission === ('audioCapture' as any) /* todo: is this needed? */) {
|
||||
// details.mediaType is a single string here (not the mediaTypes array).
|
||||
const mediaType = details?.mediaType
|
||||
|
||||
if (mediaType === 'video') {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
session.defaultSession.setPermissionCheckHandler((_webContents, permission) => {
|
||||
return (
|
||||
permission === 'media' ||
|
||||
permission === ('audioCapture' as any) /* todo: is this needed? */ ||
|
||||
permission === ('videoCapture' as any)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue