Home Download Docs Code Community
     1	/*
     2	Copyright 2014 The Perkeep Authors.
     3	
     4	Licensed under the Apache License, Version 2.0 (the "License");
     5	you may not use this file except in compliance with the License.
     6	You may obtain a copy of the License at
     7	
     8	     http://www.apache.org/licenses/LICENSE-2.0
     9	
    10	Unless required by applicable law or agreed to in writing, software
    11	distributed under the License is distributed on an "AS IS" BASIS,
    12	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13	See the License for the specific language governing permissions and
    14	limitations under the License.
    15	*/
    16	
    17	// Package clientconfig provides types related to the client configuration
    18	// file.
    19	package clientconfig // import "perkeep.org/pkg/types/clientconfig"
    20	
    21	import (
    22		"errors"
    23		"fmt"
    24		"strings"
    25	
    26		"go4.org/jsonconfig"
    27		"perkeep.org/internal/httputil"
    28	
    29		"go4.org/wkfs"
    30	)
    31	
    32	// Config holds the values from the JSON client config file.
    33	type Config struct {
    34		Servers            map[string]*Server `json:"servers"`                      // maps server alias to server config.
    35		Identity           string             `json:"identity"`                     // GPG identity.
    36		IdentitySecretRing string             `json:"identitySecretRing,omitempty"` // location of the secret ring file.
    37		IgnoredFiles       []string           `json:"ignoredFiles,omitempty"`       // list of files that pk-put should ignore.
    38	}
    39	
    40	// Server holds the values specific to each server found in the JSON client
    41	// config file.
    42	type Server struct {
    43		Server       string   `json:"server"`                 // server URL (scheme + hostname).
    44		Auth         string   `json:"auth"`                   // auth scheme and values (ex: userpass:foo:bar).
    45		IsDefault    bool     `json:"default,omitempty"`      // whether this server is the default one.
    46		TrustedCerts []string `json:"trustedCerts,omitempty"` // list of trusted certificates fingerprints.
    47	}
    48	
    49	// Alias returns the alias of the server from conf that matches server, or the
    50	// empty string if no match. A match means the server from the config is a
    51	// prefix of the input server. The longest match prevails.
    52	func (conf *Config) Alias(server string) string {
    53		longestMatch := ""
    54		serverAlias := ""
    55		for alias, serverConf := range conf.Servers {
    56			if strings.HasPrefix(server, serverConf.Server) {
    57				if len(serverConf.Server) > len(longestMatch) {
    58					longestMatch = serverConf.Server
    59					serverAlias = alias
    60				}
    61			}
    62		}
    63		return serverAlias
    64	}
    65	
    66	// GenerateClientConfig returns a client configuration which can be used to
    67	// access a server defined by the provided low-level server configuration.
    68	func GenerateClientConfig(serverConfig jsonconfig.Obj) (*Config, error) {
    69		missingConfig := func(param string) (*Config, error) {
    70			return nil, fmt.Errorf("required value for %q not found", param)
    71		}
    72	
    73		if serverConfig == nil {
    74			return nil, errors.New("server config is a required parameter")
    75		}
    76		param := "auth"
    77		auth := serverConfig.OptionalString(param, "")
    78		if auth == "" {
    79			return missingConfig(param)
    80		}
    81	
    82		// checking these early, so we can get to keyId
    83		param = "prefixes"
    84		prefixes := serverConfig.OptionalObject(param)
    85		if len(prefixes) == 0 {
    86			return missingConfig(param)
    87		}
    88		param = "/sighelper/"
    89		sighelper := prefixes.OptionalObject(param)
    90		if len(sighelper) == 0 {
    91			return missingConfig(param)
    92		}
    93		param = "handlerArgs"
    94		handlerArgs := sighelper.OptionalObject(param)
    95		if len(handlerArgs) == 0 {
    96			return missingConfig(param)
    97		}
    98		param = "keyId"
    99		keyID := handlerArgs.OptionalString(param, "")
   100		if keyID == "" {
   101			return missingConfig(param)
   102		}
   103	
   104		listen := serverConfig.OptionalString("listen", "")
   105		baseURL := serverConfig.OptionalString("baseURL", "")
   106		if listen == "" {
   107			listen = baseURL
   108		}
   109		if listen == "" {
   110			return nil, errors.New("required value for 'listen' or 'baseURL' not found")
   111		}
   112	
   113		https := serverConfig.OptionalBool("https", false)
   114		if !strings.HasPrefix(listen, "http://") && !strings.HasPrefix(listen, "https://") {
   115			if !https {
   116				listen = "http://" + listen
   117			} else {
   118				listen = "https://" + listen
   119			}
   120		}
   121	
   122		httpsCert := serverConfig.OptionalString("httpsCert", "")
   123		// TODO(mpl): See if we can detect that the cert is not self-signed,and in
   124		// that case not add it to the trustedCerts
   125		var trustedList []string
   126		if https && httpsCert != "" {
   127			certPEMBlock, err := wkfs.ReadFile(httpsCert)
   128			if err != nil {
   129				return nil, fmt.Errorf("could not read certificate: %v", err)
   130			}
   131			sig, err := httputil.CertFingerprint(certPEMBlock)
   132			if err != nil {
   133				return nil, fmt.Errorf("could not get fingerprints of certificate: %v", err)
   134			}
   135			trustedList = []string{sig}
   136		}
   137	
   138		param = "secretRing"
   139		secretRing := handlerArgs.OptionalString(param, "")
   140		if secretRing == "" {
   141			return missingConfig(param)
   142		}
   143	
   144		return &Config{
   145			Servers: map[string]*Server{
   146				"default": {
   147					Server:       listen,
   148					Auth:         auth,
   149					IsDefault:    true,
   150					TrustedCerts: trustedList,
   151				},
   152			},
   153			Identity:           keyID,
   154			IdentitySecretRing: secretRing,
   155			IgnoredFiles:       []string{".DS_Store", "*~"},
   156		}, nil
   157	}
Website layout inspired by memcached.
Content by the authors.