154 lines
3.4 KiB
Go
154 lines
3.4 KiB
Go
// Command lsf provides functions to use the lsf with the commandline.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"git.marceltransier.de/lsf"
|
|
cli "github.com/jawher/mow.cli"
|
|
"github.com/pkg/errors"
|
|
"golang.org/x/crypto/ssh/terminal"
|
|
)
|
|
|
|
var (
|
|
sessionCacheDir *string
|
|
username *string
|
|
)
|
|
|
|
var s *lsf.Session
|
|
|
|
func main() {
|
|
cacheDir, err := os.UserCacheDir()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defaultSessionCacheDir := path.Join(cacheDir, "go-lsf/sessions")
|
|
|
|
app := cli.App("lsf", "LSF Shutthe Fuckup")
|
|
|
|
sessionCacheDir = app.StringOpt("c session-cache-dir", defaultSessionCacheDir, "path to where the session tokens are cached")
|
|
username = app.StringOpt("u username", "", "username to login with")
|
|
|
|
app.Command("grades", "view your grades", cmdGrades)
|
|
//app.Command("events", "show your personalized events", cmdEvents)
|
|
//app.Command("reports", "download reports", cmdReports)
|
|
//app.Command("courses", "show courses", cmdCourses)
|
|
|
|
app.Run(os.Args)
|
|
}
|
|
|
|
func cmdGrades(cmd *cli.Cmd) {
|
|
cmd.Before = sessionNeeded
|
|
cmd.Action = func() {
|
|
noten, err := s.Noten()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println("Noten:")
|
|
noten.Print()
|
|
}
|
|
}
|
|
|
|
func sessionNeeded() {
|
|
err := os.MkdirAll(*sessionCacheDir, os.ModePerm)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if len(*username) == 0 {
|
|
var err error
|
|
*username, err = readUsername()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
s, err = session(*username)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func readUsername() (string, error) {
|
|
var username string
|
|
fmt.Print("Username: ")
|
|
_, err := fmt.Scanf("%s", &username)
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "could not read username")
|
|
}
|
|
return username, nil
|
|
}
|
|
|
|
func readPassword() (string, error) {
|
|
var password string
|
|
fmt.Print("Password: ")
|
|
b, err := terminal.ReadPassword(int(syscall.Stdin))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
fmt.Print("\n")
|
|
password = string(b)
|
|
return password, nil
|
|
}
|
|
|
|
func session(username string) (*lsf.Session, error) {
|
|
|
|
sessionPath := path.Join(*sessionCacheDir, username)
|
|
sessionFile, err := os.Open(sessionPath)
|
|
if err != nil {
|
|
pErr, ok := err.(*os.PathError)
|
|
if !ok {
|
|
return nil, err
|
|
}
|
|
errno, ok := pErr.Unwrap().(syscall.Errno)
|
|
if !ok {
|
|
return nil, err
|
|
}
|
|
if errno != syscall.ENOENT {
|
|
log.Fatal(err)
|
|
}
|
|
log.Printf("no session for %s cached\n", username)
|
|
return login(username)
|
|
}
|
|
defer sessionFile.Close()
|
|
|
|
b, err := ioutil.ReadAll(sessionFile)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "could not read session file %s", sessionPath)
|
|
}
|
|
sid := strings.TrimSuffix(string(b), "\n")
|
|
s, err := lsf.NewSessionBySID(sid)
|
|
if err == lsf.ErrInvalSID {
|
|
log.Println("session is not valid")
|
|
err := os.Remove(sessionPath)
|
|
if err != nil {
|
|
log.Println(errors.Wrap(err, "could not remove invalid session file"))
|
|
}
|
|
return login(username)
|
|
} else if err != nil {
|
|
return nil, errors.Wrap(err, "could not get session by existing sid")
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
func login(username string) (*lsf.Session, error) {
|
|
password, err := readPassword()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not read password")
|
|
}
|
|
s, err := lsf.Login(username, password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sessionPath := path.Join(*sessionCacheDir, username)
|
|
err = ioutil.WriteFile(sessionPath, []byte(s.SID), 0666)
|
|
if err != nil {
|
|
log.Println(errors.Wrap(err, "could not cache session id"))
|
|
}
|
|
return s, nil
|
|
}
|