func (s *Session) SaveToFile(location string) error {
	sessionJSON, err := json.Marshal(s)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(location, sessionJSON, 0644)
	if err != nil {
		return err
	}
	return nil
}
SaveToFile will save a json representation of the session output to a file
package core
import (
	"encoding/json"
	"fmt"
	"github.com/google/go-github/github"
	"io/ioutil"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
	"wraith/version"
	"github.com/mitchellh/go-homedir"
	"github.com/spf13/viper"
	"github.com/gin-gonic/gin"
)
const (
	StatusInitializing = "initializing"
	StatusGathering    = "gathering"
	StatusAnalyzing    = "analyzing"
	StatusFinished     = "finished"
)
var defaultIgnoreExtensions = []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff",
	".tif", ".psd", ".xcf"}
var defaultIgnorePaths = []string{"node_modules/", "vendor/bundle", "vendor/cache", "/proc/"}
var DefaultValues = map[string]interface{}{
	"bind-address":                "127.0.0.1",
	"bind-port":                   9393,
	"commit-depth":                -1,
	"config-file":                 "$HOME/.wraith/config.yaml",
	"csv":                         false,
	"debug":                       false,
	"add-org-members":             false,
	"github-enterprise-url":       "",
	"github-api-token":            "",
	"github-enterprise-api-token": "",
	"gitlab-targets":              nil,
	"gitlab-api-token":            "",
	"ignore-extension":            nil,
	"ignore-path":                 nil,
	"in-mem-clone":                false,
	"json":                        false,
	"max-file-size":               10,
	"num-threads":                 -1,
	"local-paths":                 nil,
	"scan-forks":                  false,
	"scan-tests":                  false,
	"scan-type":                   "",
	"silent":                      false,
	"confidence-level":            3,
	"signature-file":              "$HOME/.wraith/signatures/default.yaml",
	"signature-path":              "$HOME/.wraith/signatures/",
	"scan-dir":                    nil,
	"scan-file":                   nil,
	"hide-secrets":                false,
	"github-url":                  "https://api.github.com",
	"rules-url": "",
	"test-signatures":         false,
	"github-enterprise-orgs":  nil,
	"github-enterprise-repos": nil,
	"github-orgs":             nil,
	"github-repos":            nil,
	"github-users":            nil,
	"web-server":              false,
}
type Session struct {
	sync.Mutex
	BindAddress         string
	BindPort            int
	Client              IClient `json:"-"`
	CommitDepth         int
	CSVOutput           bool
	Debug               bool
	ExpandOrgs          bool
	Findings            []*Finding
	GithubAccessToken   string
	Organizations       []*github.Organization
	GithubClient        *github.Client `json:"-"`
	GithubEnterpriseURL string
	GitlabAccessToken   string
	GitlabTargets       []string
	GithubUsers         []*github.User
	HideSecrets         bool
	InMemClone          bool
	JSONOutput          bool
	MaxFileSize         int64
	Out                 *Logger `json:"-"`
	LocalPaths          []string
	Repositories        []*Repository
	Router              *gin.Engine `json:"-"`
	SignatureVersion    string
	ScanFork            bool
	ScanTests           bool
	ScanType            string
	Signatures          []*Signature
	Silent              bool
	SkippableExt        []string
	SkippablePath       []string
	Stats               *Stats
	Targets             []*Owner
	Threads             int
	WraithVersion       string
	ConfidenceLevel     int
	GithubURL           string
	GitlabURL           string
	UserDirtyNames      []string
	UserDirtyOrgs       []string
	UserDirtyRepos      []string
	UserLogins          []string
	UserOrgs            []string
	UserRepos           []string
	WebServer           bool
}
type githubRepository struct {
	Owner         *string
	ID            *int64
	Name          *string
	FullName      *string
	CloneURL      *string
	URL           *string
	DefaultBranch *string
	Description   *string
	Homepage      *string
}
func SetConfig() *viper.Viper {
	v := viper.New()
	for key, value := range DefaultValues {
		v.SetDefault(key, value)
	}
	home, err := homedir.Dir()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	v.AddConfigPath(home + "/.wraith/")
	v.SetConfigName("config")
	v.SetConfigType("yaml")
	if err := v.ReadInConfig(); err == nil {
	}
	v.AutomaticEnv()
	return v
}
func (s *Session) Initialize(v *viper.Viper, scanType string) {
	s.BindAddress = v.GetString("bind-address")
	s.BindPort = v.GetInt("bind-port")
	s.CommitDepth = setCommitDepth(v.GetFloat64("commit-depth"))
	s.CSVOutput = v.GetBool("csv")
	s.Debug = v.GetBool("debug")
	s.ExpandOrgs = v.GetBool("expaand-orgs")
	s.GithubEnterpriseURL = v.GetString("github-enterprise-url")
	s.GithubAccessToken = v.GetString("github-api-token")
	s.GitlabAccessToken = v.GetString("gitlab-api-token")
	s.GitlabTargets = v.GetStringSlice("gitlab-targets")
	s.HideSecrets = v.GetBool("hide-secrets")
	s.InMemClone = v.GetBool("in-mem-clone")
	s.JSONOutput = v.GetBool("json")
	s.MaxFileSize = v.GetInt64("max-file-size")
	s.ConfidenceLevel = v.GetInt("confidence-level")
	s.ScanFork = v.GetBool("scan-forks")
	s.ScanTests = v.GetBool("scan-tests")
	s.ScanType = scanType
	s.Silent = v.GetBool("silent")
	s.Threads = v.GetInt("num-threads")
	s.WraithVersion = version.AppVersion()
	s.WebServer = v.GetBool("web-server")
	if s.ScanType == "localGit" {
		s.LocalPaths = v.GetStringSlice("local-repos")
	} else if s.ScanType == "localPath" {
		s.LocalPaths = v.GetStringSlice("local-paths")
	}
	for _, e := range defaultIgnorePaths {
		e = strings.TrimSpace(e)
		s.SkippablePath = AppendIfMissing(s.SkippablePath, e)
	}
	for _, e := range v.GetStringSlice("ignore-path") {
		e = strings.TrimSpace(e)
		s.SkippablePath = AppendIfMissing(s.SkippablePath, e)
	}
	for _, e := range defaultIgnoreExtensions {
		s.SkippableExt = AppendIfMissing(s.SkippableExt, e)
	}
	for _, f := range v.GetStringSlice("ignore-extension") {
		f = strings.TrimSpace(f)
		s.SkippableExt = AppendIfMissing(s.SkippableExt, f)
	}
	s.InitStats()
	s.InitLogger()
	s.InitThreads()
	if !s.Silent && s.WebServer {
		s.InitRouter()
	}
	var curSig []Signature
	var combinedSig []Signature
	for _, f := range v.GetStringSlice("signature-file") {
		f = strings.TrimSpace(f)
		h := SetHomeDir(f, s)
		if PathExists(h, s) {
			curSig = LoadSignatures(h, s.ConfidenceLevel, s)
			combinedSig = append(combinedSig, curSig...)
		}
	}
	Signatures = combinedSig
}
func setCommitDepth(c float64) int {
	if c == -1 {
		return 9999999999
	}
	return int(c)
}
func (s *Session) Finish() {
	s.Stats.FinishedAt = time.Now()
	s.Stats.Status = StatusFinished
}
func (s *Session) AddTarget(target *Owner) {
	s.Lock()
	defer s.Unlock()
	for _, t := range s.Targets {
		if *target.ID == *t.ID {
			return
		}
	}
	s.Targets = append(s.Targets, target)
	s.Stats.IncrementTargets()
}
func (s *Session) AddRepository(repository *Repository) {
	s.Lock()
	defer s.Unlock()
	for _, r := range s.Repositories {
		if *repository.ID == *r.ID {
			return
		}
	}
	s.Repositories = append(s.Repositories, repository)
}
func (s *Session) AddFinding(finding *Finding) {
	s.Lock()
	defer s.Unlock()
	const MaxStrLen = 100
	s.Findings = append(s.Findings, finding)
	s.Stats.IncrementFindingsTotal()
}
func (s *Session) InitThreads() {
	if s.Threads == 0 {
		numCPUs := runtime.NumCPU()
		s.Threads = numCPUs
	}
	runtime.GOMAXPROCS(s.Threads + 2)  
}
func (s *Session) InitRouter() {
	bind := fmt.Sprintf("%s:%d", s.BindAddress, s.BindPort)
	s.Router = NewRouter(s)
	go func(sess *Session) {
		if err := sess.Router.Run(bind); err != nil {
			sess.Out.Fatal("Error when starting web server: %s\n", err)
		}
	}(s)
}