internal/pipewire: implement SecurityContext::Create
All checks were successful
Test / Create distribution (push) Successful in 36s
Test / Sandbox (push) Successful in 2m26s
Test / Hakurei (push) Successful in 3m18s
Test / Hpkg (push) Successful in 4m16s
Test / Sandbox (race detector) (push) Successful in 4m22s
Test / Hakurei (race detector) (push) Successful in 5m12s
Test / Flake checks (push) Successful in 1m27s
All checks were successful
Test / Create distribution (push) Successful in 36s
Test / Sandbox (push) Successful in 2m26s
Test / Hakurei (push) Successful in 3m18s
Test / Hpkg (push) Successful in 4m16s
Test / Sandbox (race detector) (push) Successful in 4m22s
Test / Hakurei (race detector) (push) Successful in 5m12s
Test / Flake checks (push) Successful in 1m27s
This is finally the thing we are after. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
5a5c4705dd
commit
de3fc7ba38
@ -10,6 +10,7 @@ func TestFooterCoreGeneration(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
encodingTestCases[pipewire.Footer[pipewire.FooterCoreGeneration], *pipewire.Footer[pipewire.FooterCoreGeneration]]{
|
encodingTestCases[pipewire.Footer[pipewire.FooterCoreGeneration], *pipewire.Footer[pipewire.FooterCoreGeneration]]{
|
||||||
|
|
||||||
/* recvmsg 0 */
|
/* recvmsg 0 */
|
||||||
|
|
||||||
{"sample0", samplePWContainer[1][0][2], pipewire.Footer[pipewire.FooterCoreGeneration]{
|
{"sample0", samplePWContainer[1][0][2], pipewire.Footer[pipewire.FooterCoreGeneration]{
|
||||||
@ -29,6 +30,7 @@ func TestFooterCoreGeneration(t *testing.T) {
|
|||||||
}.run(t)
|
}.run(t)
|
||||||
|
|
||||||
encodingTestCases[pipewire.Footer[pipewire.FooterClientGeneration], *pipewire.Footer[pipewire.FooterClientGeneration]]{
|
encodingTestCases[pipewire.Footer[pipewire.FooterClientGeneration], *pipewire.Footer[pipewire.FooterClientGeneration]]{
|
||||||
|
|
||||||
/* sendmsg 1 */
|
/* sendmsg 1 */
|
||||||
|
|
||||||
{"sample0", samplePWContainer[3][0][2], pipewire.Footer[pipewire.FooterClientGeneration]{
|
{"sample0", samplePWContainer[3][0][2], pipewire.Footer[pipewire.FooterClientGeneration]{
|
||||||
@ -36,6 +38,13 @@ func TestFooterCoreGeneration(t *testing.T) {
|
|||||||
// why does this not match FooterCoreGeneration sample2?
|
// why does this not match FooterCoreGeneration sample2?
|
||||||
Payload: pipewire.FooterClientGeneration{ClientGeneration: 0x23},
|
Payload: pipewire.FooterClientGeneration{ClientGeneration: 0x23},
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
|
/* sendmsg 2 */
|
||||||
|
|
||||||
|
{"sample1", samplePWContainer[6][0][2], pipewire.Footer[pipewire.FooterClientGeneration]{
|
||||||
|
Opcode: pipewire.FOOTER_CORE_OPCODE_GENERATION,
|
||||||
|
Payload: pipewire.FooterClientGeneration{ClientGeneration: 0x24},
|
||||||
|
}, nil},
|
||||||
}.run(t)
|
}.run(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +110,12 @@ func TestCoreDone(t *testing.T) {
|
|||||||
ID: 0,
|
ID: 0,
|
||||||
Sequence: pipewire.CoreSyncSequenceOffset + 3,
|
Sequence: pipewire.CoreSyncSequenceOffset + 3,
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
|
// matches the second Core::Sync sample
|
||||||
|
{"sample2", samplePWContainer[7][0][1], pipewire.CoreDone{
|
||||||
|
ID: 0,
|
||||||
|
Sequence: pipewire.CoreSyncSequenceOffset + 6,
|
||||||
|
}, nil},
|
||||||
}.run(t)
|
}.run(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,10 +165,15 @@ func TestCoreSync(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
encodingTestCases[pipewire.CoreSync, *pipewire.CoreSync]{
|
encodingTestCases[pipewire.CoreSync, *pipewire.CoreSync]{
|
||||||
{"sample", samplePWContainer[0][3][1], pipewire.CoreSync{
|
{"sample0", samplePWContainer[0][3][1], pipewire.CoreSync{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
Sequence: pipewire.CoreSyncSequenceOffset + 3,
|
Sequence: pipewire.CoreSyncSequenceOffset + 3,
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
|
{"sample1", samplePWContainer[6][1][1], pipewire.CoreSync{
|
||||||
|
ID: 0,
|
||||||
|
Sequence: pipewire.CoreSyncSequenceOffset + 6,
|
||||||
|
}, nil},
|
||||||
}.run(t)
|
}.run(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ func TestHeader(t *testing.T) {
|
|||||||
Size: 0x28, Sequence: 2, FileCount: 0,
|
Size: 0x28, Sequence: 2, FileCount: 0,
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"PW_CORE_METHOD_SYNC", samplePWContainer[0][3][0], pipewire.Header{
|
{"PW_CORE_METHOD_SYNC 0", samplePWContainer[0][3][0], pipewire.Header{
|
||||||
ID: pipewire.PW_ID_CORE,
|
ID: pipewire.PW_ID_CORE,
|
||||||
Opcode: pipewire.PW_CORE_METHOD_SYNC,
|
Opcode: pipewire.PW_CORE_METHOD_SYNC,
|
||||||
Size: 0x28, Sequence: 3, FileCount: 0,
|
Size: 0x28, Sequence: 3, FileCount: 0,
|
||||||
@ -314,33 +314,27 @@ func TestHeader(t *testing.T) {
|
|||||||
Size: 0x68, Sequence: 43, FileCount: 0,
|
Size: 0x68, Sequence: 43, FileCount: 0,
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"PW_SECURITY_CONTEXT_METHOD_CREATE", []byte{
|
/* sendmsg 2 */
|
||||||
// Id
|
|
||||||
3, 0, 0, 0,
|
|
||||||
// size
|
|
||||||
0xd8, 0, 0,
|
|
||||||
// opcode
|
|
||||||
1,
|
|
||||||
// seq
|
|
||||||
5, 0, 0, 0,
|
|
||||||
// n_fds
|
|
||||||
2, 0, 0, 0,
|
|
||||||
}, pipewire.Header{ID: 3, Opcode: pipewire.PW_SECURITY_CONTEXT_METHOD_CREATE,
|
|
||||||
Size: 0xd8, Sequence: 5, FileCount: 2}, nil},
|
|
||||||
|
|
||||||
{"PW_SECURITY_CONTEXT_METHOD_NUM", []byte{
|
{"PW_SECURITY_CONTEXT_METHOD_CREATE", samplePWContainer[6][0][0], pipewire.Header{
|
||||||
// Id
|
ID: 3,
|
||||||
0, 0, 0, 0,
|
Opcode: pipewire.PW_SECURITY_CONTEXT_METHOD_CREATE,
|
||||||
// size
|
Size: 0xd8, Sequence: 5, FileCount: 2,
|
||||||
0x28, 0, 0,
|
}, nil},
|
||||||
// opcode
|
|
||||||
2,
|
{"PW_CORE_METHOD_SYNC 1", samplePWContainer[6][1][0], pipewire.Header{
|
||||||
// seq
|
ID: pipewire.PW_ID_CORE,
|
||||||
6, 0, 0, 0,
|
Opcode: pipewire.PW_CORE_METHOD_SYNC,
|
||||||
// n_fds
|
Size: 0x28, Sequence: 6, FileCount: 0,
|
||||||
0, 0, 0, 0,
|
}, nil},
|
||||||
}, pipewire.Header{ID: 0, Opcode: pipewire.PW_SECURITY_CONTEXT_METHOD_NUM,
|
|
||||||
Size: 0x28, Sequence: 6, FileCount: 0}, nil},
|
/* recvmsg 2 */
|
||||||
|
|
||||||
|
{"PW_CORE_EVENT_DONE 2", samplePWContainer[7][0][0], pipewire.Header{
|
||||||
|
ID: pipewire.PW_ID_CORE,
|
||||||
|
Opcode: pipewire.PW_CORE_EVENT_DONE,
|
||||||
|
Size: 0x28, Sequence: 44, FileCount: 0,
|
||||||
|
}, nil},
|
||||||
}.run(t)
|
}.run(t)
|
||||||
|
|
||||||
t.Run("size range", func(t *testing.T) {
|
t.Run("size range", func(t *testing.T) {
|
||||||
|
|||||||
@ -356,30 +356,6 @@ const (
|
|||||||
PW_KEY_PROFILER_NAME = "profiler.name"
|
PW_KEY_PROFILER_NAME = "profiler.name"
|
||||||
)
|
)
|
||||||
|
|
||||||
/* pipewire/extensions/security-context.h */
|
|
||||||
|
|
||||||
const (
|
|
||||||
PW_TYPE_INTERFACE_SecurityContext = PW_TYPE_INFO_INTERFACE_BASE + "SecurityContext"
|
|
||||||
PW_SECURITY_CONTEXT_PERM_MASK = PW_PERM_RWX
|
|
||||||
PW_VERSION_SECURITY_CONTEXT = 3
|
|
||||||
|
|
||||||
PW_EXTENSION_MODULE_SECURITY_CONTEXT = PIPEWIRE_MODULE_PREFIX + "module-security-context"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PW_SECURITY_CONTEXT_EVENT_NUM = iota
|
|
||||||
|
|
||||||
PW_VERSION_SECURITY_CONTEXT_EVENTS = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PW_SECURITY_CONTEXT_METHOD_ADD_LISTENER = iota
|
|
||||||
PW_SECURITY_CONTEXT_METHOD_CREATE
|
|
||||||
PW_SECURITY_CONTEXT_METHOD_NUM
|
|
||||||
|
|
||||||
PW_VERSION_SECURITY_CONTEXT_METHODS = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
/* pipewire/type.h */
|
/* pipewire/type.h */
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@ -30,6 +30,9 @@ type (
|
|||||||
String = string
|
String = string
|
||||||
// Bytes is a byte slice representing SPA_TYPE_Bytes.
|
// Bytes is a byte slice representing SPA_TYPE_Bytes.
|
||||||
Bytes = []byte
|
Bytes = []byte
|
||||||
|
|
||||||
|
// A Fd is a signed integer value representing SPA_TYPE_Fd.
|
||||||
|
Fd Long
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -49,6 +52,9 @@ const (
|
|||||||
SizeInt Word = 4
|
SizeInt Word = 4
|
||||||
// SizeLong is the fixed, unpadded size of a [SPA_TYPE_Long] value.
|
// SizeLong is the fixed, unpadded size of a [SPA_TYPE_Long] value.
|
||||||
SizeLong Word = 8
|
SizeLong Word = 8
|
||||||
|
|
||||||
|
// SizeFd is the fixed, unpadded size of a [SPA_TYPE_Fd] value.
|
||||||
|
SizeFd = SizeLong
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Basic types */
|
/* Basic types */
|
||||||
@ -176,6 +182,15 @@ func marshalValueAppend(data []byte, v reflect.Value) ([]byte, error) {
|
|||||||
|
|
||||||
// marshalValueAppendRaw implements [MarshalAppend] on [reflect.Value] without the size prefix.
|
// marshalValueAppendRaw implements [MarshalAppend] on [reflect.Value] without the size prefix.
|
||||||
func marshalValueAppendRaw(data []byte, v reflect.Value) ([]byte, error) {
|
func marshalValueAppendRaw(data []byte, v reflect.Value) ([]byte, error) {
|
||||||
|
if v.CanInterface() {
|
||||||
|
switch c := v.Interface().(type) {
|
||||||
|
case Fd:
|
||||||
|
data = binary.NativeEndian.AppendUint32(data, SPA_TYPE_Fd)
|
||||||
|
data = binary.NativeEndian.AppendUint64(data, uint64(c))
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case reflect.Uint32:
|
case reflect.Uint32:
|
||||||
data = binary.NativeEndian.AppendUint32(data, SPA_TYPE_Id)
|
data = binary.NativeEndian.AppendUint32(data, SPA_TYPE_Id)
|
||||||
@ -312,6 +327,16 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
|
|||||||
*wireSizeP, err = u.UnmarshalPOD(data)
|
*wireSizeP, err = u.UnmarshalPOD(data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch v.Interface().(type) {
|
||||||
|
case Fd:
|
||||||
|
*wireSizeP = SizeFd
|
||||||
|
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Fd, wireSizeP); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.SetInt(int64(binary.NativeEndian.Uint64(data)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
|
|||||||
69
internal/pipewire/securitycontext.go
Normal file
69
internal/pipewire/securitycontext.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package pipewire
|
||||||
|
|
||||||
|
/* pipewire/extensions/security-context.h */
|
||||||
|
|
||||||
|
const (
|
||||||
|
PW_TYPE_INTERFACE_SecurityContext = PW_TYPE_INFO_INTERFACE_BASE + "SecurityContext"
|
||||||
|
PW_SECURITY_CONTEXT_PERM_MASK = PW_PERM_RWX
|
||||||
|
PW_VERSION_SECURITY_CONTEXT = 3
|
||||||
|
|
||||||
|
PW_EXTENSION_MODULE_SECURITY_CONTEXT = PIPEWIRE_MODULE_PREFIX + "module-security-context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PW_SECURITY_CONTEXT_EVENT_NUM = iota
|
||||||
|
|
||||||
|
PW_VERSION_SECURITY_CONTEXT_EVENTS = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PW_SECURITY_CONTEXT_METHOD_ADD_LISTENER = iota
|
||||||
|
PW_SECURITY_CONTEXT_METHOD_CREATE
|
||||||
|
PW_SECURITY_CONTEXT_METHOD_NUM
|
||||||
|
|
||||||
|
PW_VERSION_SECURITY_CONTEXT_METHODS = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecurityContextCreate is sent to create a new security context.
|
||||||
|
//
|
||||||
|
// Creates a new security context with a socket listening FD.
|
||||||
|
// PipeWire will accept new client connections on listen_fd.
|
||||||
|
//
|
||||||
|
// listen_fd must be ready to accept new connections when this
|
||||||
|
// request is sent by the client. In other words, the client must
|
||||||
|
// call bind(2) and listen(2) before sending the FD.
|
||||||
|
//
|
||||||
|
// close_fd is a FD closed by the client when PipeWire should stop
|
||||||
|
// accepting new connections on listen_fd.
|
||||||
|
//
|
||||||
|
// PipeWire must continue to accept connections on listen_fd when
|
||||||
|
// the client which created the security context disconnects.
|
||||||
|
//
|
||||||
|
// After sending this request, closing listen_fd and close_fd
|
||||||
|
// remains the only valid operation on them.
|
||||||
|
type SecurityContextCreate struct {
|
||||||
|
// The offset in the SCM_RIGHTS msg_control message to
|
||||||
|
// the fd to listen on for new connections.
|
||||||
|
ListenFd Fd
|
||||||
|
// The offset in the SCM_RIGHTS msg_control message to
|
||||||
|
// the fd used to stop listening.
|
||||||
|
CloseFd Fd
|
||||||
|
|
||||||
|
// Extra properties. These will be copied on the client
|
||||||
|
// that connects through this context.
|
||||||
|
Properties *SPADict `json:"props"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size satisfies [KnownSize] with a value computed at runtime.
|
||||||
|
func (c *SecurityContextCreate) Size() Word {
|
||||||
|
return SizePrefix +
|
||||||
|
Size(SizeFd) +
|
||||||
|
Size(SizeFd) +
|
||||||
|
c.Properties.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary satisfies [encoding.BinaryMarshaler] via [Marshal].
|
||||||
|
func (c *SecurityContextCreate) MarshalBinary() ([]byte, error) { return Marshal(c) }
|
||||||
|
|
||||||
|
// UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal].
|
||||||
|
func (c *SecurityContextCreate) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) }
|
||||||
21
internal/pipewire/securitycontext_test.go
Normal file
21
internal/pipewire/securitycontext_test.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package pipewire_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/internal/pipewire"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSecurityContextCreate(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
encodingTestCases[pipewire.SecurityContextCreate, *pipewire.SecurityContextCreate]{
|
||||||
|
{"sample", samplePWContainer[6][0][1], pipewire.SecurityContextCreate{
|
||||||
|
ListenFd: 1 /* 21: duplicated from listen_fd */, CloseFd: 0, /* 20: duplicated from close_fd */
|
||||||
|
Properties: &pipewire.SPADict{
|
||||||
|
{Key: "pipewire.sec.engine", Value: "org.flatpak"},
|
||||||
|
{Key: "pipewire.access", Value: "restricted"},
|
||||||
|
},
|
||||||
|
}, nil},
|
||||||
|
}.run(t)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user