-
-
Notifications
You must be signed in to change notification settings - Fork 418
/
errors.go
259 lines (220 loc) · 10.5 KB
/
errors.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// Copyright (c) 2021 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package whatsmeow
import (
"errors"
"fmt"
"net/http"
waBinary "go.mau.fi/whatsmeow/binary"
)
// Miscellaneous errors
var (
ErrNoSession = errors.New("can't encrypt message for device: no signal session established")
ErrIQTimedOut = errors.New("info query timed out")
ErrNotConnected = errors.New("websocket not connected")
ErrNotLoggedIn = errors.New("the store doesn't contain a device JID")
ErrMessageTimedOut = errors.New("timed out waiting for message send response")
ErrAlreadyConnected = errors.New("websocket is already connected")
ErrQRAlreadyConnected = errors.New("GetQRChannel must be called before connecting")
ErrQRStoreContainsID = errors.New("GetQRChannel can only be called when there's no user ID in the client's Store")
ErrNoPushName = errors.New("can't send presence without PushName set")
ErrNoPrivacyToken = errors.New("no privacy token stored")
ErrAppStateUpdate = errors.New("server returned error updating app state")
)
// Errors that happen while confirming device pairing
var (
ErrPairInvalidDeviceIdentityHMAC = errors.New("invalid device identity HMAC in pair success message")
ErrPairInvalidDeviceSignature = errors.New("invalid device signature in pair success message")
ErrPairRejectedLocally = errors.New("local PrePairCallback rejected pairing")
)
// PairProtoError is included in an events.PairError if the pairing failed due to a protobuf error.
type PairProtoError struct {
Message string
ProtoErr error
}
func (err *PairProtoError) Error() string {
return fmt.Sprintf("%s: %v", err.Message, err.ProtoErr)
}
func (err *PairProtoError) Unwrap() error {
return err.ProtoErr
}
// PairDatabaseError is included in an events.PairError if the pairing failed due to being unable to save the credentials to the device store.
type PairDatabaseError struct {
Message string
DBErr error
}
func (err *PairDatabaseError) Error() string {
return fmt.Sprintf("%s: %v", err.Message, err.DBErr)
}
func (err *PairDatabaseError) Unwrap() error {
return err.DBErr
}
var (
// ErrProfilePictureUnauthorized is returned by GetProfilePictureInfo when trying to get the profile picture of a user
// whose privacy settings prevent you from seeing their profile picture (status code 401).
ErrProfilePictureUnauthorized = errors.New("the user has hidden their profile picture from you")
// ErrProfilePictureNotSet is returned by GetProfilePictureInfo when the given user or group doesn't have a profile
// picture (status code 404).
ErrProfilePictureNotSet = errors.New("that user or group does not have a profile picture")
// ErrGroupInviteLinkUnauthorized is returned by GetGroupInviteLink if you don't have the permission to get the link (status code 401).
ErrGroupInviteLinkUnauthorized = errors.New("you don't have the permission to get the group's invite link")
// ErrNotInGroup is returned by group info getting methods if you're not in the group (status code 403).
ErrNotInGroup = errors.New("you're not participating in that group")
// ErrGroupNotFound is returned by group info getting methods if the group doesn't exist (status code 404).
ErrGroupNotFound = errors.New("that group does not exist")
// ErrInviteLinkInvalid is returned by methods that use group invite links if the invite link is malformed.
ErrInviteLinkInvalid = errors.New("that group invite link is not valid")
// ErrInviteLinkRevoked is returned by methods that use group invite links if the invite link was valid, but has been revoked and can no longer be used.
ErrInviteLinkRevoked = errors.New("that group invite link has been revoked")
// ErrBusinessMessageLinkNotFound is returned by ResolveBusinessMessageLink if the link doesn't exist or has been revoked.
ErrBusinessMessageLinkNotFound = errors.New("that business message link does not exist or has been revoked")
// ErrContactQRLinkNotFound is returned by ResolveContactQRLink if the link doesn't exist or has been revoked.
ErrContactQRLinkNotFound = errors.New("that contact QR link does not exist or has been revoked")
// ErrInvalidImageFormat is returned by SetGroupPhoto if the given photo is not in the correct format.
ErrInvalidImageFormat = errors.New("the given data is not a valid image")
// ErrMediaNotAvailableOnPhone is returned by DecryptMediaRetryNotification if the given event contains error code 2.
ErrMediaNotAvailableOnPhone = errors.New("media no longer available on phone")
// ErrUnknownMediaRetryError is returned by DecryptMediaRetryNotification if the given event contains an unknown error code.
ErrUnknownMediaRetryError = errors.New("unknown media retry error")
// ErrInvalidDisappearingTimer is returned by SetDisappearingTimer if the given timer is not one of the allowed values.
ErrInvalidDisappearingTimer = errors.New("invalid disappearing timer provided")
)
// Some errors that Client.SendMessage can return
var (
ErrBroadcastListUnsupported = errors.New("sending to non-status broadcast lists is not yet supported")
ErrUnknownServer = errors.New("can't send message to unknown server")
ErrRecipientADJID = errors.New("message recipient must be a user JID with no device part")
ErrServerReturnedError = errors.New("server returned error")
ErrInvalidInlineBotID = errors.New("invalid inline bot ID")
)
type DownloadHTTPError struct {
*http.Response
}
func (dhe DownloadHTTPError) Error() string {
return fmt.Sprintf("download failed with status code %d", dhe.StatusCode)
}
func (dhe DownloadHTTPError) Is(other error) bool {
var otherDHE DownloadHTTPError
return errors.As(other, &otherDHE) && dhe.StatusCode == otherDHE.StatusCode
}
// Some errors that Client.Download can return
var (
ErrMediaDownloadFailedWith403 = DownloadHTTPError{Response: &http.Response{StatusCode: 403}}
ErrMediaDownloadFailedWith404 = DownloadHTTPError{Response: &http.Response{StatusCode: 404}}
ErrMediaDownloadFailedWith410 = DownloadHTTPError{Response: &http.Response{StatusCode: 410}}
ErrNoURLPresent = errors.New("no url present")
ErrFileLengthMismatch = errors.New("file length does not match")
ErrTooShortFile = errors.New("file too short")
ErrInvalidMediaHMAC = errors.New("invalid media hmac")
ErrInvalidMediaEncSHA256 = errors.New("hash of media ciphertext doesn't match")
ErrInvalidMediaSHA256 = errors.New("hash of media plaintext doesn't match")
ErrUnknownMediaType = errors.New("unknown media type")
ErrNothingDownloadableFound = errors.New("didn't find any attachments in message")
)
var (
ErrOriginalMessageSecretNotFound = errors.New("original message secret key not found")
ErrNotEncryptedReactionMessage = errors.New("given message isn't an encrypted reaction message")
ErrNotPollUpdateMessage = errors.New("given message isn't a poll update message")
)
type wrappedIQError struct {
HumanError error
IQError error
}
func (err *wrappedIQError) Error() string {
return err.HumanError.Error()
}
func (err *wrappedIQError) Is(other error) bool {
return errors.Is(other, err.HumanError)
}
func (err *wrappedIQError) Unwrap() error {
return err.IQError
}
func wrapIQError(human, iq error) error {
return &wrappedIQError{human, iq}
}
// IQError is a generic error container for info queries
type IQError struct {
Code int
Text string
ErrorNode *waBinary.Node
RawNode *waBinary.Node
}
// Common errors returned by info queries for use with errors.Is
var (
ErrIQBadRequest error = &IQError{Code: 400, Text: "bad-request"}
ErrIQNotAuthorized error = &IQError{Code: 401, Text: "not-authorized"}
ErrIQForbidden error = &IQError{Code: 403, Text: "forbidden"}
ErrIQNotFound error = &IQError{Code: 404, Text: "item-not-found"}
ErrIQNotAllowed error = &IQError{Code: 405, Text: "not-allowed"}
ErrIQNotAcceptable error = &IQError{Code: 406, Text: "not-acceptable"}
ErrIQGone error = &IQError{Code: 410, Text: "gone"}
ErrIQResourceLimit error = &IQError{Code: 419, Text: "resource-limit"}
ErrIQLocked error = &IQError{Code: 423, Text: "locked"}
ErrIQRateOverLimit error = &IQError{Code: 429, Text: "rate-overlimit"}
ErrIQInternalServerError error = &IQError{Code: 500, Text: "internal-server-error"}
ErrIQServiceUnavailable error = &IQError{Code: 503, Text: "service-unavailable"}
ErrIQPartialServerError error = &IQError{Code: 530, Text: "partial-server-error"}
)
func parseIQError(node *waBinary.Node) error {
var err IQError
err.RawNode = node
val, ok := node.GetOptionalChildByTag("error")
if ok {
err.ErrorNode = &val
ag := val.AttrGetter()
err.Code = ag.OptionalInt("code")
err.Text = ag.OptionalString("text")
}
return &err
}
func (iqe *IQError) Error() string {
if iqe.Code == 0 {
if iqe.ErrorNode != nil {
return fmt.Sprintf("info query returned unknown error: %s", iqe.ErrorNode.XMLString())
} else if iqe.RawNode != nil {
return fmt.Sprintf("info query returned unexpected response: %s", iqe.RawNode.XMLString())
} else {
return "unknown info query error"
}
}
return fmt.Sprintf("info query returned status %d: %s", iqe.Code, iqe.Text)
}
func (iqe *IQError) Is(other error) bool {
otherIQE, ok := other.(*IQError)
if !ok {
return false
} else if iqe.Code != 0 && otherIQE.Code != 0 {
return otherIQE.Code == iqe.Code && otherIQE.Text == iqe.Text
} else if iqe.ErrorNode != nil && otherIQE.ErrorNode != nil {
return iqe.ErrorNode.XMLString() == otherIQE.ErrorNode.XMLString()
} else {
return false
}
}
// ElementMissingError is returned by various functions that parse XML elements when a required element is missing.
type ElementMissingError struct {
Tag string
In string
}
func (eme *ElementMissingError) Error() string {
return fmt.Sprintf("missing <%s> element in %s", eme.Tag, eme.In)
}
var ErrIQDisconnected = &DisconnectedError{Action: "info query"}
// DisconnectedError is returned if the websocket disconnects before an info query or other request gets a response.
type DisconnectedError struct {
Action string
Node *waBinary.Node
}
func (err *DisconnectedError) Error() string {
return fmt.Sprintf("websocket disconnected before %s returned response", err.Action)
}
func (err *DisconnectedError) Is(other error) bool {
otherDisc, ok := other.(*DisconnectedError)
if !ok {
return false
}
return otherDisc.Action == err.Action
}