// CertificateLockFile adds a new certificate lock on the given Client and // Config that ensures that a server's certificate is signed by the same CA // from connection-to-connection. This is helpful when connecting to servers // with self-signed certificates. // // If filename does not exist, the server's certificate chain will be written // to that file. If it does exist, certificates will be read from that file and // added to RootCAs in config's TLSConfig. // // Example: // // if firstConnectionToServer { // // Allow self-signed certificates to be accepted on the initial // // connection. // config.TLSConfig.InsecureSkipVerify = true // } // gumbleutil.CertificateLockFile(client, &config, filename) // // if err := client.Connect(); err != nil { // panic(err) // } func CertificateLockFile(client *gumble.Client, config *gumble.Config, filename string) (gumble.Detacher, error) { if file, err := os.Open(filename); err == nil { defer file.Close() if config.TLSConfig.RootCAs == nil { config.TLSConfig.RootCAs = x509.NewCertPool() } if data, err := ioutil.ReadAll(file); err == nil { config.TLSConfig.RootCAs.AppendCertsFromPEM(data) } return nil, nil } return client.Attach(Listener{ Connect: func(e *gumble.ConnectEvent) { tlsClient, ok := e.Client.Conn().(*tls.Conn) if !ok { return } serverCerts := tlsClient.ConnectionState().PeerCertificates file, err := os.Create(filename) if err != nil { return } block := pem.Block{ Type: "CERTIFICATE", } for _, cert := range serverCerts { block.Bytes = cert.Raw pem.Encode(file, &block) } file.Close() }, }), nil }
// UserGroups fetches the group names the given user belongs to in the given // channel. The slice of group names sent via the returned channel. On error, // the returned channel is closed without without sending a slice. func UserGroups(client *gumble.Client, user *gumble.User, channel *gumble.Channel) <-chan []string { ch := make(chan []string) if !user.IsRegistered() { close(ch) return ch } var detacher gumble.Detacher listener := Listener{ Disconnect: func(e *gumble.DisconnectEvent) { detacher.Detach() close(ch) }, ChannelChange: func(e *gumble.ChannelChangeEvent) { if e.Channel == channel && e.Type.Has(gumble.ChannelChangeRemoved) { detacher.Detach() close(ch) } }, PermissionDenied: func(e *gumble.PermissionDeniedEvent) { if e.Channel == channel && e.Type == gumble.PermissionDeniedPermission && (e.Permission&gumble.PermissionWrite) != 0 { detacher.Detach() close(ch) } }, ACL: func(e *gumble.ACLEvent) { if e.ACL.Channel != channel { return } var names []string for _, g := range e.ACL.Groups { if (g.UsersAdd[user.UserID] != nil || g.UsersInherited[user.UserID] != nil) && g.UsersRemove[user.UserID] == nil { names = append(names, g.Name) } } detacher.Detach() ch <- names close(ch) }, } detacher = client.Attach(&listener) channel.RequestACL() return ch }
func New(client *gumble.Client) *State { l := lua.NewState() state := &State{ Client: client, LState: l, listeners: make(map[string][]lua.LValue), } t := l.NewTable() t.RawSetString("On", luar.New(l, state.apiOn)) t.RawSetString("Disconnect", luar.New(l, state.apiDisconnect)) state.table = t l.SetGlobal("piepan", t) { s := l.NewTable() s.RawSetString("New", luar.New(l, state.apiAudioNew)) s.RawSetString("IsPlaying", luar.New(l, state.apiAudioIsPlaying)) s.RawSetString("Current", luar.New(l, state.apiAudioCurrent)) s.RawSetString("NewTarget", luar.New(l, state.apiAudioNewTarget)) s.RawSetString("SetTarget", luar.New(l, state.apiAudioSetTarget)) s.RawSetString("Bitrate", luar.New(l, state.apiAudioBitrate)) s.RawSetString("SetBitrate", luar.New(l, state.apiAudioSetBitrate)) t.RawSetString("Audio", s) } { s := l.NewTable() s.RawSetString("New", luar.New(l, state.apiTimerNew)) t.RawSetString("Timer", s) } { s := l.NewTable() s.RawSetString("New", luar.New(l, state.apiProcessNew)) t.RawSetString("Process", s) } client.Attach(state) return state }