-
Notifications
You must be signed in to change notification settings - Fork 58
/
twofactor.go
138 lines (122 loc) · 3.77 KB
/
twofactor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package goinsta
import (
"encoding/json"
"fmt"
"github.com/Davincible/goinsta/v3/utilities"
)
type TwoFactorInfo struct {
insta *Instagram
ID int64 `json:"pk"`
Username string `json:"username"`
ElegibleForMultipleTotp bool `json:"elegible_for_multiple_totp"`
ObfuscatedPhoneNr string `json:"obfuscated_phone_number"`
PendingTrustedNotification bool `json:"pending_trusted_notification"`
ShouldOptInTrustedDevice bool `json:"should_opt_in_trusted_device_option"`
ShowMessengerCodeOption bool `json:"show_messenger_code_option"`
ShowTrustedDeviceOption bool `json:"show_trusted_device_option"`
SMSNotAllowedReason string `json:"sms_not_allowed_reason"`
SMSTwoFactorOn bool `json:"sms_two_factor_on"`
TotpTwoFactorOn bool `json:"totp_two_factor_on"`
WhatsappTwoFactorOn bool `json:"whatsapp_two_factor_on"`
TwoFactorIdentifier string `json:"two_factor_identifier"`
PhoneVerificationSettings phoneVerificationSettings `json:"phone_verification_settings"`
}
type phoneVerificationSettings struct {
MaxSMSCount int `json:"max_sms_count"`
ResendSMSDelaySec int `json:"resend_sms_delay_sec"`
RobocallAfterMaxSms bool `json:"robocall_after_max_sms"`
RobocallCountDownSec int `json:"robocall_count_down_time_sec"`
}
// Login2FA allows for a login through 2FA
// You can either provide a code directly by passing it as a parameter, or
// goinsta can generate one for you as long as the TOTP seed is set.
func (info *TwoFactorInfo) Login2FA(in ...string) error {
insta := info.insta
var code string
if len(in) > 0 {
code = in[0]
} else if info.insta.totp == nil || info.insta.totp.Seed == "" {
return Err2FANoCode
} else {
otp, err := utilities.GenTOTP(insta.totp.Seed)
if err != nil {
return fmt.Errorf("Failed to generate 2FA OTP code: %w", err)
}
code = otp
}
data, err := json.Marshal(
map[string]string{
"verification_code": code,
"phone_id": insta.fID,
"two_factor_identifier": info.TwoFactorIdentifier,
"username": insta.user,
"trust_this_device": "1",
"guid": insta.uuid,
"device_id": insta.dID,
"waterfall_id": generateUUID(),
"verification_method": "3",
},
)
if err != nil {
return err
}
body, _, err := insta.sendRequest(
&reqOptions{
Endpoint: url2FALogin,
IsPost: true,
Query: generateSignature(data),
IgnoreHeaders: []string{
"Ig-U-Shbts",
"Ig-U-Shbid",
"Ig-U-Rur",
"Authorization",
},
ExtraHeaders: map[string]string{
"X-Ig-Www-Claim": "0",
"Ig-Intended-User-Id": "0",
},
},
)
if err != nil {
return err
}
err = insta.parseLogin(body)
if err != nil {
return err
}
err = insta.OpenApp()
return err
}
// Check2FATrusted checks whether the device has been trusted.
// When you enable 2FA, you can verify, or trust, the device with one of your
// other devices. This method will check if this device has been trusted.
// if so, it will login, if not, it will return an error.
// The android app calls this method every 3 seconds
func (info *TwoFactorInfo) Check2FATrusted() error {
insta := info.insta
body, _, err := insta.sendRequest(
&reqOptions{
Endpoint: url2FACheckTrusted,
Query: map[string]string{
"two_factor_identifier": info.TwoFactorIdentifier,
"username": insta.user,
"device_id": insta.dID,
},
},
)
if err != nil {
return err
}
var stat struct {
ReviewStatus int `json:"review_status"`
Status string `json:"status"`
}
if err = json.Unmarshal(body, &stat); err != nil {
return err
}
if stat.ReviewStatus == 0 {
return fmt.Errorf("two factor authentication not yet verified")
}
err = info.Login2FA("")
return err
}