auth.go 3.1 KB

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