-
Notifications
You must be signed in to change notification settings - Fork 16
/
auth.go
115 lines (82 loc) · 3.06 KB
/
auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* DudelDu
*
* Copyright 2016 Matthias Ladkau. All rights reserved.
*
* This Source Code Form is subject to the terms of the MIT
* License, If a copy of the MIT License was not distributed with this
* file, You can obtain one at https://opensource.org/licenses/MIT.
*/
/*
Package dudeldu is a simple audio streaming server using the SHOUTcast protocol.
Server
Server is the main server object which runs a shoutcast server instance.
Using a WaitGroup a client can wait for the start and shutdown of the server.
Incoming new connections are served with a ConnectionHandler method. The
default implementation for this is the HandleRequest method of the
DefaultRequestHandler object.
DefaultRequestHandler
DefaultRequestHandler is the default request handler implementation for the
DudelDu server. DefaultRequestHandler has a customizable ServeRequest function.
ServeRequest is called once a request was successfully decoded.
The default implementation supports sending meta data while streaming audio. The
metadata implementation is according to:
http://www.smackfu.com/stuff/programming/shoutcast.html
Playlists
Playlists provide the data which is send to the client. A simple implementation
will just read .mp3 files and send them in chunks (via the Frame() method) to
the client.
A request handler uses a PlaylistFactory to produce a Playlist for each new
connection.
*/
package dudeldu
import (
"encoding/base64"
"regexp"
)
/*
requestAuthPattern is the pattern which is used to extract the request authentication
(i case-insensitive / m multi-line mode: ^ and $ match begin/end line)
*/
var requestAuthPattern = regexp.MustCompile("(?im)^Authorization: Basic (\\S+).*$")
/*
checkAuth checks the authentication header of a client request.
*/
func (drh *DefaultRequestHandler) checkAuth(bufStr string, clientString string) (string, string, bool) {
auth := ""
res := requestAuthPattern.FindStringSubmatch(bufStr)
origBufStr, hasAuth := drh.authPeers.Get(clientString)
if len(res) > 1 {
// Decode authentication
b, err := base64.StdEncoding.DecodeString(res[1])
if err != nil {
drh.logger.PrintDebug("Invalid request (cannot decode authentication): ", bufStr)
return auth, bufStr, false
}
auth = string(b)
// Authorize request
if auth != drh.auth && drh.auth != "" {
drh.logger.PrintDebug("Wrong authentication:", auth)
return auth, bufStr, false
}
// Peer is now authorized store this so it can connect again
drh.authPeers.Put(clientString, bufStr)
} else if drh.auth != "" && !hasAuth {
// No authorization
drh.logger.PrintDebug("No authentication found")
return auth, bufStr, false
} else if bufStr == "" && hasAuth {
// Workaround for strange clients like VLC which send first the
// authentication then connect again on a different port and just
// expect the stream
bufStr = origBufStr.(string)
// Get again the authentication
res = requestAuthPattern.FindStringSubmatch(bufStr)
if len(res) > 1 {
if b, err := base64.StdEncoding.DecodeString(res[1]); err == nil {
auth = string(b)
}
}
}
return auth, bufStr, true
}