2019-10-05 20:32:39 +02:00
|
|
|
package lsf
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2019-10-06 19:20:57 +02:00
|
|
|
"regexp"
|
2019-10-05 20:32:39 +02:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
2019-10-06 19:20:57 +02:00
|
|
|
// Error variables
|
|
|
|
var (
|
|
|
|
ErrInvalSID error = errors.New("invalid session id")
|
|
|
|
)
|
|
|
|
|
|
|
|
// Session contains the session id and whatever this obscure asi token is.
|
2019-10-05 20:32:39 +02:00
|
|
|
type Session struct {
|
|
|
|
SID string
|
2019-10-06 19:20:57 +02:00
|
|
|
// ASI is a string you somehow have to pass to some endpoints.
|
|
|
|
ASI string
|
2019-10-05 20:32:39 +02:00
|
|
|
}
|
|
|
|
|
2019-10-06 19:20:57 +02:00
|
|
|
// Valid checks if the session id of the session is valid
|
2019-10-05 20:32:39 +02:00
|
|
|
func (s *Session) Valid() (bool, error) {
|
|
|
|
client := &http.Client{}
|
2019-10-06 19:20:57 +02:00
|
|
|
// GET the logged in mail page.
|
|
|
|
// If correctly logged in there is a logout button.
|
|
|
|
// Otherwise there is a login button.
|
2019-10-05 20:32:39 +02:00
|
|
|
req, err := http.NewRequest("GET", "https://lsf.hs-worms.de/qisserver/rds?state=user&type=8&topitem=functions&breadCrumbSource=portal", nil)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Wrap(err, "could not prepare the request")
|
|
|
|
}
|
|
|
|
req.Header.Add("Cookie", fmt.Sprintf("JSESSIONID=%s", s.SID))
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Wrap(err, "could not do the request")
|
|
|
|
}
|
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Wrap(err, "could not read the response body")
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Contains(string(b), "<u>L</u>ogout") {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
if strings.Contains(string(b), "<u>L</u>ogin") {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return false, errors.New("unexpected response body")
|
|
|
|
}
|
|
|
|
|
2019-10-06 19:20:57 +02:00
|
|
|
// Login tries to login with the given username and password.
|
|
|
|
// If successful a new Session with the session id and asi
|
|
|
|
// will be created and returned.
|
2019-10-05 20:32:39 +02:00
|
|
|
func Login(username, password string) (*Session, error) {
|
|
|
|
client := &http.Client{
|
|
|
|
CheckRedirect: func(req *http.Request, via []*http.Request) error { // don't follow redirects
|
|
|
|
return http.ErrUseLastResponse
|
|
|
|
},
|
|
|
|
}
|
|
|
|
form := url.Values{}
|
|
|
|
form.Add("asdf", username) // who wrote this backend? lol
|
|
|
|
form.Add("fdsa", password)
|
|
|
|
form.Add("submit", "Login")
|
|
|
|
req, err := http.NewRequest("POST", "https://lsf.hs-worms.de/qisserver/rds?state=user&type=1&category=auth.login&startpage=portal.vm&breadCrumbSource=portal", strings.NewReader(form.Encode()))
|
|
|
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not prepare the login request")
|
|
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not do the login request")
|
|
|
|
}
|
|
|
|
if resp.StatusCode == 302 {
|
|
|
|
for _, c := range resp.Cookies() {
|
|
|
|
if c.Name == "JSESSIONID" {
|
2019-10-06 19:20:57 +02:00
|
|
|
asi, err := asi(c.Value)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not get asi")
|
|
|
|
}
|
2019-10-05 20:32:39 +02:00
|
|
|
return &Session{
|
|
|
|
SID: c.Value,
|
2019-10-06 19:20:57 +02:00
|
|
|
ASI: asi,
|
2019-10-05 20:32:39 +02:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, errors.New("no session cookie found")
|
|
|
|
}
|
|
|
|
if resp.StatusCode == 200 {
|
|
|
|
return nil, errors.New("wrong credentials") // TODO or other errors
|
|
|
|
}
|
|
|
|
return nil, errors.New("unexpected response status code")
|
|
|
|
}
|
2019-10-06 19:20:57 +02:00
|
|
|
|
|
|
|
// NewSessionBySID checks whether the given session id is valid and if so
|
|
|
|
// a new Session with the session id and asi will be created and returned.
|
|
|
|
func NewSessionBySID(sid string) (*Session, error) {
|
|
|
|
s := &Session{
|
|
|
|
SID: sid,
|
|
|
|
}
|
|
|
|
valid, err := s.Valid()
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not check session")
|
|
|
|
}
|
|
|
|
if !valid {
|
|
|
|
return nil, ErrInvalSID
|
|
|
|
}
|
|
|
|
asi, err := asi(sid)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not get asi")
|
|
|
|
}
|
|
|
|
return &Session{
|
|
|
|
SID: sid,
|
|
|
|
ASI: asi,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func asi(sid string) (string, error) {
|
|
|
|
client := &http.Client{}
|
|
|
|
// GET Request with JESSIONID cookie to sitemap endpoint
|
|
|
|
req, err := http.NewRequest("GET", "https://lsf.hs-worms.de/qisserver/rds?state=sitemap&topitem=leer&breadCrumbSource=portal", nil)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrap(err, "could not prepare the request")
|
|
|
|
}
|
|
|
|
req.Header.Add("Cookie", fmt.Sprintf("JSESSIONID=%s", sid))
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrap(err, "could not do the request")
|
|
|
|
}
|
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrap(err, "could not read the response body")
|
|
|
|
}
|
|
|
|
// The asi is in some links as GET parameter.
|
|
|
|
// Filter it with regexp
|
|
|
|
re := regexp.MustCompile(`asi=([^"]+)`)
|
|
|
|
match := re.FindSubmatch(b)
|
|
|
|
if len(match) != 2 {
|
|
|
|
return "", errors.New("no asi found")
|
|
|
|
}
|
|
|
|
return string(match[1]), nil
|
|
|
|
}
|