1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package engine
5
6import (
7	"io"
8
9	"github.com/keybase/client/go/libkb"
10	keybase1 "github.com/keybase/client/go/protocol/keybase1"
11	"github.com/keybase/saltpack"
12)
13
14// SaltpackVerify is an engine.
15type SaltpackVerify struct {
16	libkb.Contextified
17	arg *SaltpackVerifyArg
18}
19
20// SaltpackVerifyArg are engine args.
21type SaltpackVerifyArg struct {
22	Sink   io.WriteCloser
23	Source io.Reader
24	Opts   keybase1.SaltpackVerifyOptions
25}
26
27// NewSaltpackVerify creates a SaltpackVerify engine.
28func NewSaltpackVerify(g *libkb.GlobalContext, arg *SaltpackVerifyArg) *SaltpackVerify {
29	return &SaltpackVerify{
30		arg:          arg,
31		Contextified: libkb.NewContextified(g),
32	}
33}
34
35// Name is the unique engine name.
36func (e *SaltpackVerify) Name() string {
37	return "SaltpackVerify"
38}
39
40// Prereqs returns the engine prereqs.
41func (e *SaltpackVerify) Prereqs() Prereqs {
42	return Prereqs{}
43}
44
45// RequiredUIs returns the required UIs.
46func (e *SaltpackVerify) RequiredUIs() []libkb.UIKind {
47	return []libkb.UIKind{
48		libkb.SaltpackUIKind,
49	}
50}
51
52// SubConsumers returns the other UI consumers for this engine.
53func (e *SaltpackVerify) SubConsumers() []libkb.UIConsumer {
54	return []libkb.UIConsumer{&SaltpackSenderIdentify{}}
55}
56
57// Run starts the engine.
58func (e *SaltpackVerify) Run(m libkb.MetaContext) error {
59	if len(e.arg.Opts.Signature) > 0 {
60		return e.detached(m)
61	}
62	return e.attached(m)
63}
64
65func (e *SaltpackVerify) attached(m libkb.MetaContext) error {
66	hook := func(key saltpack.SigningPublicKey) error {
67		return e.identifySender(m, key)
68	}
69	return libkb.SaltpackVerify(m.G(), e.arg.Source, e.arg.Sink, hook)
70}
71
72func (e *SaltpackVerify) detached(m libkb.MetaContext) error {
73	hook := func(key saltpack.SigningPublicKey) error {
74		return e.identifySender(m, key)
75	}
76	return libkb.SaltpackVerifyDetached(m.G(), e.arg.Source, e.arg.Opts.Signature, hook)
77}
78
79func (e *SaltpackVerify) identifySender(m libkb.MetaContext, key saltpack.SigningPublicKey) (err error) {
80	defer m.Trace("SaltpackVerify#identifySender", &err)()
81
82	kid := libkb.SigningPublicKeyToKeybaseKID(key)
83	spsiArg := SaltpackSenderIdentifyArg{
84		publicKey: kid,
85		reason: keybase1.IdentifyReason{
86			Reason: "Identify who signed this message",
87			Type:   keybase1.IdentifyReasonType_VERIFY,
88		},
89		userAssertion: e.arg.Opts.SignedBy,
90	}
91
92	spsiEng := NewSaltpackSenderIdentify(m.G(), &spsiArg)
93	if err = RunEngine2(m, spsiEng); err != nil {
94		return err
95	}
96
97	if senderTypeIsSuccessful(spsiEng.Result().SenderType) {
98		arg := keybase1.SaltpackVerifySuccessArg{
99			Sender:     spsiEng.Result(),
100			SigningKID: kid,
101		}
102		return m.UIs().SaltpackUI.SaltpackVerifySuccess(m.Ctx(), arg)
103	}
104
105	arg := keybase1.SaltpackVerifyBadSenderArg{
106		Sender:     spsiEng.Result(),
107		SigningKID: kid,
108	}
109	// This will return an error if --force is not given.
110	return m.UIs().SaltpackUI.SaltpackVerifyBadSender(m.Ctx(), arg)
111}
112
113func senderTypeIsSuccessful(senderType keybase1.SaltpackSenderType) bool {
114	return (senderType == keybase1.SaltpackSenderType_NOT_TRACKED ||
115		senderType == keybase1.SaltpackSenderType_UNKNOWN ||
116		senderType == keybase1.SaltpackSenderType_ANONYMOUS ||
117		senderType == keybase1.SaltpackSenderType_TRACKING_OK ||
118		senderType == keybase1.SaltpackSenderType_SELF)
119}
120