mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-20 07:39:56 +00:00
Fix ExtendedClipboard auto-request by advertising all actions in Caps
This commit is contained in:
@@ -10,6 +10,7 @@ type vncServer interface{}
|
|||||||
|
|
||||||
func (e *Engine) updateVNC(_ *mgmProto.SSHConfig) error { return nil }
|
func (e *Engine) updateVNC(_ *mgmProto.SSHConfig) error { return nil }
|
||||||
|
|
||||||
|
// updateVNCServerAuth is a no-op on platforms without a VNC server.
|
||||||
func (e *Engine) updateVNCServerAuth(_ *mgmProto.VNCAuth) {}
|
func (e *Engine) updateVNCServerAuth(_ *mgmProto.VNCAuth) {}
|
||||||
|
|
||||||
func (e *Engine) stopVNCServer() error { return nil }
|
func (e *Engine) stopVNCServer() error { return nil }
|
||||||
|
|||||||
@@ -52,11 +52,16 @@ const (
|
|||||||
extClipMaxPayload = extClipMaxText + 1024
|
extClipMaxPayload = extClipMaxText + 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
// buildExtClipCaps emits the Caps payload advertising the formats we accept
|
// buildExtClipCaps emits the Caps payload. The flags word advertises every
|
||||||
// and our maximum size per format. One uint32 size follows the flags word
|
// action we support in the high byte (Caps + Request + Peek + Notify +
|
||||||
// for each format bit set, in ascending bit order.
|
// Provide) and every format we accept in the low 16 bits. noVNC uses these
|
||||||
|
// action bits to decide whether to auto-Request on Notify; without
|
||||||
|
// Request in our Caps it silently drops our Notify messages. After the
|
||||||
|
// flags word we emit one uint32 max size per format bit set, in ascending
|
||||||
|
// bit order.
|
||||||
func buildExtClipCaps() []byte {
|
func buildExtClipCaps() []byte {
|
||||||
flags := extClipActionCaps | extClipFormatText
|
flags := extClipActionCaps | extClipActionRequest | extClipActionPeek |
|
||||||
|
extClipActionNotify | extClipActionProvide | extClipFormatText
|
||||||
payload := make([]byte, 4+4)
|
payload := make([]byte, 4+4)
|
||||||
binary.BigEndian.PutUint32(payload[0:4], flags)
|
binary.BigEndian.PutUint32(payload[0:4], flags)
|
||||||
binary.BigEndian.PutUint32(payload[4:8], uint32(extClipMaxText))
|
binary.BigEndian.PutUint32(payload[4:8], uint32(extClipMaxText))
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ func TestBuildExtClipCaps(t *testing.T) {
|
|||||||
require.Len(t, payload, 8, "Caps with one format should be 4 bytes flags + 4 bytes size")
|
require.Len(t, payload, 8, "Caps with one format should be 4 bytes flags + 4 bytes size")
|
||||||
|
|
||||||
flags := binary.BigEndian.Uint32(payload[0:4])
|
flags := binary.BigEndian.Uint32(payload[0:4])
|
||||||
assert.Equal(t, extClipActionCaps, flags&extClipActionMask, "action should be Caps")
|
// noVNC checks individual action bits in our Caps to decide whether to
|
||||||
|
// auto-Request on Notify, so all supported actions must be advertised.
|
||||||
|
assert.NotZero(t, flags&extClipActionCaps, "Caps action bit must be set")
|
||||||
|
assert.NotZero(t, flags&extClipActionRequest, "Request action bit must be set")
|
||||||
|
assert.NotZero(t, flags&extClipActionPeek, "Peek action bit must be set")
|
||||||
|
assert.NotZero(t, flags&extClipActionNotify, "Notify action bit must be set")
|
||||||
|
assert.NotZero(t, flags&extClipActionProvide, "Provide action bit must be set")
|
||||||
assert.Equal(t, extClipFormatText, flags&extClipFormatMask, "should advertise text format")
|
assert.Equal(t, extClipFormatText, flags&extClipFormatMask, "should advertise text format")
|
||||||
|
|
||||||
maxSize := binary.BigEndian.Uint32(payload[4:8])
|
maxSize := binary.BigEndian.Uint32(payload[4:8])
|
||||||
|
|||||||
@@ -877,24 +877,32 @@ func (s *session) handleExtCutText(payloadLen uint32) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
case extClipActionProvide:
|
case extClipActionProvide:
|
||||||
if len(rest) == 0 {
|
return s.handleExtClipProvide(flags, rest)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
text, err := parseExtClipProvideText(flags, rest)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Debugf("parse ext clipboard provide: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if text != "" {
|
|
||||||
s.injector.SetClipboard(text)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
default:
|
default:
|
||||||
s.log.Debugf("unknown ext clipboard action 0x%x", action)
|
s.log.Debugf("unknown ext clipboard action 0x%x", action)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleExtClipProvide decodes a Provide payload and pushes the recovered
|
||||||
|
// text into the host clipboard. Errors and other unsupported formats (RTF,
|
||||||
|
// HTML, etc.) are swallowed so a malformed message doesn't tear down the
|
||||||
|
// session.
|
||||||
|
func (s *session) handleExtClipProvide(flags uint32, payload []byte) error {
|
||||||
|
if len(payload) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
text, err := parseExtClipProvideText(flags, payload)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Debugf("parse ext clipboard provide: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if text != "" {
|
||||||
|
s.injector.SetClipboard(text)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// sendExtClipProvideText answers an inbound Request(text) with the current
|
// sendExtClipProvideText answers an inbound Request(text) with the current
|
||||||
// host clipboard contents, capped to extClipMaxText.
|
// host clipboard contents, capped to extClipMaxText.
|
||||||
func (s *session) sendExtClipProvideText() error {
|
func (s *session) sendExtClipProvideText() error {
|
||||||
|
|||||||
Reference in New Issue
Block a user