Example #1
0
// tokenAuthenticate uses the token authentication method to log in to the API, returning
// a session user and a pair of client/server errors
func tokenAuthenticate(req *http.Request) (*data.User, *data.Session, error, error) {
	// Token for authentication
	var token string

	// Check for empty authorization header
	if req.Header.Get("Authorization") == "" {
		// If no header, check for credentials via querystring parameters
		token = req.URL.Query().Get("s")
	} else {
		// Fetch credentials from HTTP Basic auth
		tempToken, _, err := basicCredentials(req.Header.Get("Authorization"))
		if err != nil {
			return nil, nil, err, nil
		}

		// Copy credentials
		token = tempToken
	}

	// Check if token is blank
	if token == "" {
		return nil, nil, ErrNoToken, nil
	}

	// Attempt to load session by key
	session := new(data.Session)
	session.Key = token
	if err := session.Load(); err != nil {
		// Check for invalid user
		if err == sql.ErrNoRows {
			return nil, nil, ErrInvalidToken, nil
		}

		// Server error
		return nil, nil, nil, err
	}

	// Attempt to load associated user by user ID from session
	user := new(data.User)
	user.ID = session.UserID
	if err := user.Load(); err != nil {
		// Server error
		return nil, nil, nil, err
	}

	// Update session expiration date by 1 week
	session.Expire = time.Now().Add(7 * 24 * time.Hour).Unix()
	if err := session.Update(); err != nil {
		return nil, nil, nil, err
	}

	// No errors, return session user and session
	return user, session, nil, nil
}
Example #2
0
// PostLogout destroys an existing session from the wavepipe API,
// and returns a HTTP status and JSON.
func PostLogout(w http.ResponseWriter, r *http.Request) {
	// Retrieve render
	ren := context.Get(r, CtxRender).(*render.Render)

	// Attempt to retrieve session from context
	session := new(data.Session)
	if tempSession := context.Get(r, CtxSession); tempSession != nil {
		session = tempSession.(*data.Session)
	} else {
		// No session stored in context
		log.Println("api: no session stored in request context!")
		ren.JSON(w, 500, serverErr)
		return
	}

	// Check API version
	if version, ok := mux.Vars(r)["version"]; ok {
		// Check if this API call is supported in the advertised version
		if !apiVersionSet.Has(version) {
			ren.JSON(w, 400, errRes(400, "unsupported API version: "+version))
			return
		}
	}

	// Destroy the current API session
	if session != nil {
		if err := session.Delete(); err != nil {
			log.Println(err)
			ren.JSON(w, 500, serverErr)
			return
		}
	}

	// HTTP 200 OK with JSON
	ren.JSON(w, 200, ErrorResponse{})
	return
}
Example #3
0
// subsonicAuthenticate uses the Subsonic authentication method to log in to the API, returning
// only a pair of client/server errors
func subsonicAuthenticate(req *http.Request) (*data.User, *data.Session, error, error) {
	// Check for required credentials via querystring
	query := req.URL.Query()
	username := query.Get("u")
	password := query.Get("p")

	// Check if username or password is blank
	if username == "" || password == "" {
		return nil, nil, subsonic.ErrBadCredentials, nil
	}

	// Check for Subsonic version
	version := query.Get("v")
	if version == "" {
		return nil, nil, subsonic.ErrMissingParameter, nil
	}

	// TODO: reevaluate this strategy in the future, but for now, we will use a user's wavepipe session
	// TODO: key as their Subsonic password.  This will mean that the username and session key are passed on
	// TODO: every request, but also means that no more database schema must be added for Subsonic authentication.

	// Check for "enc:" prefix, specifying a hex-encoded password
	if strings.HasPrefix(password, "enc:") {
		// Decode hex string
		out, err := hex.DecodeString(password[4:])
		if err != nil {
			return nil, nil, nil, err
		}

		password = string(out)
	}

	// Attempt to load session by key passed via Subsonic password parameter
	session := new(data.Session)
	session.Key = password
	if err := session.Load(); err != nil {
		// Check for invalid user
		if err == sql.ErrNoRows {
			return nil, nil, subsonic.ErrBadCredentials, nil
		}

		// Server error
		return nil, nil, nil, err
	}

	// Attempt to load associated user by username from Subsonic username parameter
	user := new(data.User)
	user.Username = username
	if err := user.Load(); err != nil {
		// Server error
		return nil, nil, nil, err
	}

	// Update session expiration date by 1 week
	session.Expire = time.Now().Add(7 * 24 * time.Hour).Unix()
	if err := session.Update(); err != nil {
		return nil, nil, nil, err
	}

	// No errors, return no user or session because the emulated Subsonic API is read-only
	return nil, nil, nil, nil
}