1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"time"
8
9	keybase1 "github.com/keybase/client/go/protocol/keybase1"
10)
11
12type Session struct {
13	Contextified
14	token    string
15	csrf     string
16	deviceID keybase1.DeviceID
17	valid    bool
18	uid      keybase1.UID
19	username *NormalizedUsername
20	mtime    time.Time
21	checked  bool
22}
23
24func newSession(g *GlobalContext) *Session {
25	return &Session{Contextified: Contextified{g}}
26}
27
28// NewSessionThin creates a minimal (thin) session of just the uid and username.
29// Clients of the daemon that use the session protocol need this.
30func NewSessionThin(uid keybase1.UID, username NormalizedUsername, token string) *Session {
31	// XXX should this set valid to true?  daemon won't return a
32	// session unless valid is true, so...
33	return &Session{uid: uid, username: &username, token: token, valid: true}
34}
35
36func (s *Session) IsLoggedIn() bool {
37	return s.valid
38}
39
40func (s *Session) Clone() *Session {
41	if s == nil {
42		return nil
43	}
44	ret := *s
45	if ret.username != nil {
46		un := *ret.username
47		ret.username = &un
48	}
49	return &ret
50}
51
52func (s *Session) GetUsername() *NormalizedUsername {
53	return s.username
54}
55
56func (s *Session) GetUID() keybase1.UID {
57	return s.uid
58}
59
60func (s *Session) GetDeviceID() keybase1.DeviceID {
61	return s.deviceID
62}
63
64func (s *Session) GetToken() string {
65	return s.token
66}
67
68func (s *Session) GetCsrf() string {
69	return s.csrf
70}
71
72func (s *Session) APIArgs() (token, csrf string) {
73	return s.token, s.csrf
74}
75
76func (s *Session) SetUsername(username NormalizedUsername) {
77	s.username = &username
78}
79
80func (s *Session) SetLoggedIn(sessionID, csrfToken string, username NormalizedUsername, uid keybase1.UID, deviceID keybase1.DeviceID) error {
81	s.valid = true
82	s.uid = uid
83	s.username = &username
84	s.token = sessionID
85	s.csrf = csrfToken
86	s.deviceID = deviceID
87	s.mtime = time.Now()
88	return nil
89}
90
91func (s *Session) SetDeviceProvisioned(devid keybase1.DeviceID) error {
92	s.G().Log.Debug("Local Session: setting provisioned device id: %s", devid)
93	s.deviceID = devid
94	return nil
95}
96
97func (s *Session) IsRecent() bool {
98	if s.mtime.IsZero() {
99		return false
100	}
101	return time.Since(s.mtime) < time.Hour
102}
103
104// Invalidate marks the session as invalid and posts a logout
105// notification.
106func (s *Session) Invalidate() {
107	s.G().Log.Debug("invalidating session")
108	s.valid = false
109	s.mtime = time.Time{}
110	s.token = ""
111	s.csrf = ""
112	s.checked = false
113}
114
115func (s *Session) HasSessionToken() bool {
116	return len(s.token) > 0
117}
118
119func (s *Session) IsValid() bool {
120	return s.valid
121}
122
123type SessionTokener struct {
124	session, csrf string
125}
126
127func (s *SessionTokener) Tokens() (session, csrf string) {
128	return s.session, s.csrf
129}
130
131func NewSessionTokener(mctx MetaContext) (*SessionTokener, error) {
132	resp, err := mctx.G().API.Post(mctx, APIArg{
133		Endpoint:    "new_session",
134		SessionType: APISessionTypeREQUIRED,
135	})
136	if err != nil {
137		return nil, err
138	}
139
140	session, err := resp.Body.AtKey("session").GetString()
141	if err != nil {
142		return nil, err
143	}
144	csrf, err := resp.Body.AtKey("csrf_token").GetString()
145	if err != nil {
146		return nil, err
147	}
148
149	return &SessionTokener{
150		session: session,
151		csrf:    csrf,
152	}, nil
153}
154