// 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
}
Beispiel #2
0
func fetchYoutubeInfo(client *gumble.Client, id string) {
	var info videoInfo

	// Fetch + parse video info
	url := fmt.Sprintf("http://gdata.youtube.com/feeds/api/videos/%s?v=2&alt=jsonc", id)
	if resp, err := http.Get(url); err != nil {
		return
	} else {
		decoder := json.NewDecoder(resp.Body)
		if err := decoder.Decode(&info); err != nil {
			return
		}
		info.Data.Duration *= time.Second
		resp.Body.Close()
	}

	// Create response string
	var buffer bytes.Buffer
	if err := outputTemplate.Execute(&buffer, info); err != nil {
		return
	}
	message := gumble.TextMessage{
		Channels: []*gumble.Channel{
			client.Self.Channel,
		},
		Message: buffer.String(),
	}
	client.Send(&message)
}
Beispiel #3
0
// 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
}
Beispiel #4
0
func New(client *gumble.Client) (*Stream, error) {
	s := &Stream{
		client:          client,
		userStreams:     make(map[uint32]openal.Source),
		sourceFrameSize: client.Config.GetAudioFrameSize(),
	}

	s.deviceSource = openal.CaptureOpenDevice("", gumble.AudioSampleRate, openal.FormatMono16, uint32(s.sourceFrameSize))

	s.deviceSink = openal.OpenDevice("")
	s.contextSink = s.deviceSink.CreateContext()
	s.contextSink.Activate()
	s.buffer = make([]byte, gumble.AudioMaximumFrameSize)

	s.link = client.AttachAudio(s)

	return s, nil
}
Beispiel #5
0
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
}