~kris/9p

disco

8e24774a4f3cbb208a7fa8cf667a953526dfc336 — Sean Hinchee 7 years ago 3173d64
migrate to ndb config in $home/lib/disco.ndb ;; clean up some error messages and factotum handling
5 files changed, 112 insertions(+), 50 deletions(-)

M README.md
M TODO
M config.go
M helper.go
M main.go
M README.md => README.md +1 -3
@@ 2,7 2,7 @@

Fork of theboxmage's [discord-cli](https://github.com/theboxmage/discordcli)

JSON config is in `$home/lib/disco.cfg` for setting password, should be made automatically after first run.
NDB config is in `$home/lib/disco.ndb` for setting password, should be made automatically after first run.

## Install



@@ 15,8 15,6 @@ go get bitbucket.org/henesy/disco

## Problems

* JSON

* PM's are temporarily disabled

* Does not create accounts for you, this still needs to be done in a browser/app

M TODO => TODO +2 -4
@@ 8,13 8,11 @@ Commands:

Features:

* remove JSON config

* read $home/lib/discord.face for profile picture (or just face?)

* delete disco.cfg on failure to log in for 400 bad request: password does not match
* delete disco.ndb on failure to log in for 400 bad request: password does not match

* verify proper permissions -rw------- 0600 for discord.cfg
* runtime verify proper permissions -rw------- 0600 for discord.ndb

* [done] if ``` entered, allow multi-line message (composition)


M config.go => config.go +106 -40
@@ 2,29 2,67 @@ package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/user"
	//	"golang.org/x/crypto/ssh/terminal"
sc	"strconv"
	"strings"
	"bitbucket.org/mischief/libauth"
	"github.com/mischief/ndb"
)

// Types of auth we can do ­ add handling for new modes to atoam()
type AuthModes int
const (
	Pass		AuthModes = iota
	Factotum
	Unknown		// Placeholder
)

//Configuration is a struct that contains all configuration fields
type Configuration struct {
	Username       string `json:"username"`
	MessageDefault bool   `json:"messagedefault"`
	Messages       int    `json:"messages"`
	CompletionChar string `json:"completionchar"`
	TimeCompChar   string `json:"timecompchar"`
	password       string
	AuthMode		AuthModes
	Username		string
	LoadBacklog		bool
	Messages		int
	PromptChar		string
	TimestampChar	string
	password		string
}

// Config is the global configuration of discord-cli
var Config Configuration

//GetConfig retrieves configuration file from $home/lib/disco.cfg, if it doesn't exist it calls CreateConfig()
var ConfigPath string = "/lib/disco.ndb"

// Convert a string such as "true" into true
func atob(s string) bool {
	s = strings.ToLower(s)

	if s == "true" {
		return true
	}

	return false
}

// Convert a string such as "factotum" into factotum
func atoam(s string) AuthModes {
	s = strings.ToLower(s)
	
	if s == "pass" {
		return Pass
	}
	
	if s == "factotum" {
		return Factotum
	}
	
	return Unknown
}

//GetConfig retrieves configuration file from $home/lib/disco.ndb, if it doesn't exist it calls CreateConfig()
func GetConfig() {
	//Get User
Start:


@@ 33,59 71,66 @@ Start:
		log.Fatal(err)
	}

	//Get File
	file, err := os.Open(usr.HomeDir + "/lib/disco.cfg")
	// Get File
	file, err := os.Open(usr.HomeDir + ConfigPath)

	if err != nil {
		log.Println("Creating new config file")
		CreateConfig()
		goto Start
	}

	//Decode File
	decoder := json.NewDecoder(file)
	err = decoder.Decode(&Config)
	file.Close()

	// Decode File
	ndb, err := ndb.Open(usr.HomeDir + ConfigPath)
	if err != nil {
		log.Println("Failed to decode configuration file")
		log.Fatalf("Error: %s", err)
		log.Fatal("error: Could not ")
	}
	
	Config.Username = ndb.Search("username", "").Search("username")
	Config.AuthMode = atoam(ndb.Search("auth", "").Search("auth"))
	
	if Config.AuthMode == Pass {
		Config.password = ndb.Search("username", "").Search("password")
	}

	Config.LoadBacklog		= atob(ndb.Search("loadbacklog", "").Search("loadbacklog"))
	Config.Messages, _		= sc.Atoi(ndb.Search("messages", "").Search("messages"))
	Config.PromptChar		= ndb.Search("promptchar", "").Search("promptchar")
	Config.TimestampChar	= ndb.Search("timestampchar", "").Search("timestampchar")

}

//CreateConfig creates folder inside $home and makes a new empty configuration file
func CreateConfig() {
	//Get User
	// Get User
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}

	var EmptyStruct Configuration
	//Set Default values
	// Set Default values
	fmt.Print("Input your email: ")
	scan := bufio.NewScanner(os.Stdin)
	scan.Scan()

	EmptyStruct.Username = scan.Text()
	EmptyStruct.Messages = 10
	EmptyStruct.MessageDefault = true
	EmptyStruct.CompletionChar = ">"
	EmptyStruct.TimeCompChar = ">"
	raw := fmt.Sprintf("auth=pass\nloadbacklog=true\nmessages=10\npromptchar=→\ntimestampchar=>\n\nusername=%s	password=\n", scan.Text())

	//Create File
	os.Mkdir(usr.HomeDir+"/lib", 0775)
	file, err := os.Create(usr.HomeDir + "/lib/disco.cfg")
	// Create File
	os.Mkdir(usr.HomeDir + "/lib", 0775)
	
	file, err := os.Create(usr.HomeDir + ConfigPath)
	
	if err != nil {
		log.Fatalln(err)
	}
	
	file.Chmod(0600)

	//Marshall EmptyStruct
	raw, err := json.Marshal(EmptyStruct)
	if err != nil {
		log.Fatalln(err)
	}
	// PrintToFile
	_, err = file.Write([]byte(raw))

	//PrintToFile
	_, err = file.Write(raw)
	if err != nil {
		log.Fatalln(err)
	}


@@ 93,20 138,41 @@ func CreateConfig() {
	file.Close()
}

//CheckState checks the current state for essential missing information, errors will fail the program
// CheckState checks the current state for essential missing information, errors will fail the program
func CheckState() {
	//Get User
	usr, err := user.Current()

	if err != nil {
		log.Fatal(err)
	}

	if Config.Username == "" {
		log.Fatalln("No Username Specified, please edit " + usr.HomeDir + "/lib/disco.cfg")
		log.Fatalln("Error: No Username Specified, please edit " + usr.HomeDir + ConfigPath)
	}
	userPwd, err := libauth.Getuserpasswd("proto=pass service=discord user=%s server=discordapp.com", Config.Username)
	if err != nil {
		log.Fatal(err)
	
	// Check and handle password loading
	switch(Config.AuthMode){
	case Factotum:
		// Acquire password from factotum
		userPwd, err := libauth.Getuserpasswd("proto=pass service=discord user=%s server=discordapp.com", Config.Username)

		if err != nil {
			// Factotum didn't get anything
			fmt.Fprintln(os.Stderr, "Warning: No success getting key from factotum, consider disabling it in ndb.")
			fmt.Fprintln(os.Stderr, "Libauth gave: ", err)
		} else {
			Config.password = userPwd.Password
		}

	case Unknown:
		log.Fatalln("Error: incorrect, or no, authmode specified via auth= config tuple. Consider: auth=(pass factotum).")

	default:
		// Password is already loaded in auth=pass mode
	}
	
	if(Config.password == "") {
		log.Fatalln("Error: No password loaded, cannot auth. Are you missing a factotum key or password= tuple?")
	}
	Config.password = userPwd.Password
}

M helper.go => helper.go +2 -2
@@ 133,11 133,11 @@ func MessagePrint(Time, Username, Content string) {
	//var Color color.Attribute
	log.SetFlags(0)
	if *hideTimeStamp {
		log.Printf("%s %s %s\n", Username, Config.CompletionChar, content)
		log.Printf("%s %s %s\n", Username, Config.PromptChar, content)
	} else {
		TimeStamp, _ := time.Parse(time.RFC3339, Time)
		LocalTime := TimeStamp.Local().Format("2006/01/02 15:04:05")
		log.Printf("%s %s %s %s %s\n", LocalTime, Config.TimeCompChar, Username, Config.CompletionChar, content)
		log.Printf("%s %s %s %s %s\n", LocalTime, Config.TimestampChar, Username, Config.PromptChar, content)

	}
	log.SetFlags(log.LstdFlags)

M main.go => main.go +1 -1
@@ 139,7 139,7 @@ func InitWindow() {
//ShowContent shows default Channel content
func ShowContent() {
	Header()
	if Config.MessageDefault {
	if Config.LoadBacklog {
		State.RetrieveMessages(Config.Messages)
		PrintMessages(Config.Messages)
	}