github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/upspinsos/service.go (about)

     1  // Copyright 2018 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"flag"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"regexp"
    15  	"strings"
    16  )
    17  
    18  var (
    19  	upspinConfigDir = flag.String("configdir", filepath.Join(os.Getenv("HOME"), "upspin"), "path for Upspin config file")
    20  	upspinKeyDir    = flag.String("keydir", filepath.Join(os.Getenv("HOME"), ".ssh"), "path for username directory to hold key files")
    21  )
    22  
    23  type UpspinService struct {
    24  	Configured bool
    25  	User       string
    26  	Dir        string
    27  	Store      string
    28  	Seed       string
    29  }
    30  
    31  func makeUserDirectories(dir string) error {
    32  	if _, err := os.Stat(dir); os.IsNotExist(err) {
    33  		if err := os.MkdirAll(dir, 0777); err != nil {
    34  			return err
    35  		}
    36  		return filepath.Walk(dir, func(name string, info os.FileInfo, err error) error {
    37  			if err == nil {
    38  				err = os.Chown(name, 1000, 1000)
    39  			}
    40  			return err
    41  		})
    42  	}
    43  	return nil
    44  }
    45  
    46  func getFileData(path string) map[string]string {
    47  	userData := make(map[string]string)
    48  	b, err := ioutil.ReadFile(path)
    49  	if err != nil {
    50  		// start in unconfigured mode using empty map
    51  		return userData
    52  	}
    53  	// regex for finding key-val separator ": [remote,]" and port ":443"
    54  	splitpoint := regexp.MustCompile("(: )(.*,|)")
    55  	port := regexp.MustCompile("(:443)")
    56  	for _, s := range strings.Split(string(b), "\n") {
    57  		s := port.ReplaceAllString(s, "")
    58  		keyval := splitpoint.Split(s, -1)
    59  		if len(keyval) == 2 {
    60  			userData[keyval[0]] = keyval[1]
    61  		}
    62  	}
    63  	return userData
    64  }
    65  
    66  func (us UpspinService) setFileData(path string) error {
    67  	f, err := os.Create(path)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	defer f.Close()
    72  	f.WriteString(fmt.Sprintf("username: %v\n", us.User))
    73  	// hardcoded default server prefix and suffix
    74  	f.WriteString(fmt.Sprintf("dirserver: remote,%v:443\n", us.Dir))
    75  	f.WriteString(fmt.Sprintf("storeserver: remote,%v:443\n", us.Store))
    76  	f.WriteString("packing: ee\n")
    77  	return nil
    78  }
    79  
    80  func (us UpspinService) setKeys(path string) error {
    81  	// check if keys are set already
    82  	f, err := os.Open(path)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	defer f.Close()
    87  	args := []string{"keygen", fmt.Sprintf("-secretseed=%v", us.Seed)}
    88  	// if the directory is populated, rotate the keys instead of generating new ones
    89  	// this method of appending args is ugly, but they have to be in this specific order:
    90  	// upspin keygen <-rotate> -secretseed=<seed> path
    91  	if _, err = f.Readdir(1); err == nil {
    92  		args = append(args, "-rotate")
    93  	}
    94  
    95  	return exec.Command("upspin", append(args, path)...).Run()
    96  }
    97  
    98  func (us *UpspinService) Update() {
    99  	data := getFileData(filepath.Join(*upspinConfigDir, "config"))
   100  	us.User = data["username"]
   101  	us.Dir = data["dirserver"]
   102  	us.Store = data["storeserver"]
   103  }
   104  
   105  func (us *UpspinService) ToggleFlag() {
   106  	us.Configured = !us.Configured
   107  }
   108  
   109  func (us *UpspinService) SetConfig(new UpspinAcctJsonMsg) error {
   110  	us.User = new.User
   111  	us.Dir = new.Dir
   112  	us.Store = new.Store
   113  	us.Seed = new.Seed
   114  	makeUserDirectories(*upspinConfigDir)
   115  	if err := us.setFileData(filepath.Join(*upspinConfigDir, "config")); err != nil {
   116  		return err
   117  	}
   118  	fullKeyPath := filepath.Join(*upspinKeyDir, us.User)
   119  	makeUserDirectories(fullKeyPath)
   120  	if err := us.setKeys(fullKeyPath); err != nil {
   121  		return err
   122  	}
   123  	return nil
   124  }
   125  
   126  func NewUpspinService() (*UpspinService, error) {
   127  	data := getFileData(filepath.Join(*upspinConfigDir, "config"))
   128  	config := false
   129  	if len(data) > 0 {
   130  		config = true
   131  	}
   132  	return &UpspinService{
   133  		Configured: config,
   134  		User:       data["username"],
   135  		Dir:        data["dirserver"],
   136  		Store:      data["storeserver"],
   137  		Seed:       "",
   138  	}, nil
   139  }