1package libkb
2
3import (
4	"time"
5
6	"github.com/keybase/client/go/kbun"
7	"github.com/keybase/client/go/protocol/keybase1"
8)
9
10type deviceForUsersRet struct {
11	AppStatusEmbed
12	UserConfigs []deviceForUser `json:"user_configs"`
13}
14type deviceForUser struct {
15	UID      keybase1.UID      `json:"uid"`
16	DeviceID keybase1.DeviceID `json:"device_id"`
17	OK       bool              `json:"ok"`
18	Username string            `json:"username"`
19}
20
21// GetAllProvisionedUsernames looks into the current config.json file, and
22// finds all usernames that are currently provisioned on this device. Then, it
23// asks the server to filter out revoked devices or reset users.
24func GetAllProvisionedUsernames(mctx MetaContext) (current NormalizedUsername, all []NormalizedUsername, err error) {
25	mctx = mctx.WithLogTag("GAPU")
26	defer mctx.Trace("GetAllProvisionedUsernames", &err)()
27
28	currentUC, otherUCs, err := mctx.G().Env.GetConfig().GetAllUserConfigs()
29	if err != nil {
30		return current, nil, err
31	}
32
33	var userConfigs []deviceForUser
34	if currentUC != nil {
35		userConfigs = append(userConfigs, deviceForUser{UID: currentUC.GetUID(), DeviceID: currentUC.GetDeviceID()})
36	}
37	for _, uc := range otherUCs {
38		userConfigs = append(userConfigs, deviceForUser{UID: uc.GetUID(), DeviceID: uc.GetDeviceID()})
39	}
40
41	if len(userConfigs) == 0 {
42		mctx.Debug("GAPU: no userConfigs to lookup")
43		return current, nil, nil
44	}
45
46	payload := make(JSONPayload)
47	payload["user_configs"] = userConfigs
48	arg := APIArg{
49		Endpoint:       "device/for_users",
50		JSONPayload:    payload,
51		SessionType:    APISessionTypeNONE,
52		InitialTimeout: 5 * time.Second,
53		RetryCount:     3,
54	}
55
56	resp := deviceForUsersRet{}
57	err = mctx.G().API.PostDecode(mctx, arg, &resp)
58	var configsForReturn []deviceForUser
59	if _, ok := err.(APINetError); ok {
60		// We got a network error but we can still return offline results.
61		mctx.Info("Failed to check server for revoked in GAPU: %+v", err)
62		// Put together a fake response from the offline data:
63		if currentUC != nil {
64			configsForReturn = append(configsForReturn, deviceForUser{Username: string(currentUC.Name), OK: true})
65		}
66		for _, uc := range otherUCs {
67			configsForReturn = append(configsForReturn, deviceForUser{Username: string(uc.Name), OK: true})
68		}
69	} else if err != nil {
70		return "", nil, err
71	} else {
72		configsForReturn = resp.UserConfigs
73	}
74
75	for _, userConfig := range configsForReturn {
76		if userConfig.OK {
77			nu := kbun.NewNormalizedUsername(userConfig.Username)
78			all = append(all, nu)
79			if currentUC != nil && nu == currentUC.GetUsername() {
80				current = nu
81			}
82		}
83	}
84
85	return current, all, nil
86}
87