1/2
This commit is contained in:
parent
ff6d9f23e3
commit
0cf7c09ed5
35
vendor/go.mau.fi/whatsmeow/appstate.go
vendored
35
vendor/go.mau.fi/whatsmeow/appstate.go
vendored
@ -223,6 +223,41 @@ func (cli *Client) dispatchAppState(mutation appstate.Mutation, fullSync bool, e
|
||||
Action: mutation.Action.GetUserStatusMuteAction(),
|
||||
FromFullSync: fullSync,
|
||||
}
|
||||
case appstate.IndexLabelEdit:
|
||||
act := mutation.Action.GetLabelEditAction()
|
||||
eventToDispatch = &events.LabelEdit{
|
||||
Timestamp: ts,
|
||||
LabelID: mutation.Index[1],
|
||||
Action: act,
|
||||
FromFullSync: fullSync,
|
||||
}
|
||||
case appstate.IndexLabelAssociationChat:
|
||||
if len(mutation.Index) < 3 {
|
||||
return
|
||||
}
|
||||
jid, _ = types.ParseJID(mutation.Index[2])
|
||||
act := mutation.Action.GetLabelAssociationAction()
|
||||
eventToDispatch = &events.LabelAssociationChat{
|
||||
JID: jid,
|
||||
Timestamp: ts,
|
||||
LabelID: mutation.Index[1],
|
||||
Action: act,
|
||||
FromFullSync: fullSync,
|
||||
}
|
||||
case appstate.IndexLabelAssociationMessage:
|
||||
if len(mutation.Index) < 6 {
|
||||
return
|
||||
}
|
||||
jid, _ = types.ParseJID(mutation.Index[2])
|
||||
act := mutation.Action.GetLabelAssociationAction()
|
||||
eventToDispatch = &events.LabelAssociationMessage{
|
||||
JID: jid,
|
||||
Timestamp: ts,
|
||||
LabelID: mutation.Index[1],
|
||||
MessageID: mutation.Index[3],
|
||||
Action: act,
|
||||
FromFullSync: fullSync,
|
||||
}
|
||||
}
|
||||
if storeUpdateError != nil {
|
||||
cli.Log.Errorf("Failed to update device store after app state mutation: %v", storeUpdateError)
|
||||
|
99
vendor/go.mau.fi/whatsmeow/armadillomessage.go
vendored
Normal file
99
vendor/go.mau.fi/whatsmeow/armadillomessage.go
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2024 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 (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.mau.fi/whatsmeow/binary/armadillo"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waCommon"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMsgApplication"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMsgTransport"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
)
|
||||
|
||||
func (cli *Client) handleDecryptedArmadillo(info *types.MessageInfo, decrypted []byte, retryCount int) bool {
|
||||
dec, err := decodeArmadillo(decrypted)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Failed to decode armadillo message from %s: %v", info.SourceString(), err)
|
||||
return false
|
||||
}
|
||||
dec.Info = *info
|
||||
dec.RetryCount = retryCount
|
||||
if dec.Transport.GetProtocol().GetAncillary().GetSkdm() != nil {
|
||||
if !info.IsGroup {
|
||||
cli.Log.Warnf("Got sender key distribution message in non-group chat from %s", info.Sender)
|
||||
} else {
|
||||
skdm := dec.Transport.GetProtocol().GetAncillary().GetSkdm()
|
||||
cli.handleSenderKeyDistributionMessage(info.Chat, info.Sender, skdm.AxolotlSenderKeyDistributionMessage)
|
||||
}
|
||||
}
|
||||
if dec.Message != nil {
|
||||
cli.dispatchEvent(&dec)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func decodeArmadillo(data []byte) (dec events.FBMessage, err error) {
|
||||
var transport waMsgTransport.MessageTransport
|
||||
err = proto.Unmarshal(data, &transport)
|
||||
if err != nil {
|
||||
return dec, fmt.Errorf("failed to unmarshal transport: %w", err)
|
||||
}
|
||||
dec.Transport = &transport
|
||||
if transport.GetPayload() == nil {
|
||||
return
|
||||
}
|
||||
application, err := transport.GetPayload().Decode()
|
||||
if err != nil {
|
||||
return dec, fmt.Errorf("failed to unmarshal application: %w", err)
|
||||
}
|
||||
dec.Application = application
|
||||
if application.GetPayload() == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch typedContent := application.GetPayload().GetContent().(type) {
|
||||
case *waMsgApplication.MessageApplication_Payload_CoreContent:
|
||||
err = fmt.Errorf("unsupported core content payload")
|
||||
case *waMsgApplication.MessageApplication_Payload_Signal:
|
||||
err = fmt.Errorf("unsupported signal payload")
|
||||
case *waMsgApplication.MessageApplication_Payload_ApplicationData:
|
||||
err = fmt.Errorf("unsupported application data payload")
|
||||
case *waMsgApplication.MessageApplication_Payload_SubProtocol:
|
||||
var protoMsg proto.Message
|
||||
var subData *waCommon.SubProtocol
|
||||
switch subProtocol := typedContent.SubProtocol.GetSubProtocol().(type) {
|
||||
case *waMsgApplication.MessageApplication_SubProtocolPayload_ConsumerMessage:
|
||||
dec.Message, err = subProtocol.Decode()
|
||||
case *waMsgApplication.MessageApplication_SubProtocolPayload_BusinessMessage:
|
||||
dec.Message = (*armadillo.Unsupported_BusinessApplication)(subProtocol.BusinessMessage)
|
||||
case *waMsgApplication.MessageApplication_SubProtocolPayload_PaymentMessage:
|
||||
dec.Message = (*armadillo.Unsupported_PaymentApplication)(subProtocol.PaymentMessage)
|
||||
case *waMsgApplication.MessageApplication_SubProtocolPayload_MultiDevice:
|
||||
dec.Message, err = subProtocol.Decode()
|
||||
case *waMsgApplication.MessageApplication_SubProtocolPayload_Voip:
|
||||
dec.Message = (*armadillo.Unsupported_Voip)(subProtocol.Voip)
|
||||
case *waMsgApplication.MessageApplication_SubProtocolPayload_Armadillo:
|
||||
dec.Message, err = subProtocol.Decode()
|
||||
default:
|
||||
return dec, fmt.Errorf("unsupported subprotocol type: %T", subProtocol)
|
||||
}
|
||||
if protoMsg != nil {
|
||||
err = proto.Unmarshal(subData.GetPayload(), protoMsg)
|
||||
if err != nil {
|
||||
return dec, fmt.Errorf("failed to unmarshal application subprotocol payload (%T v%d): %w", protoMsg, subData.GetVersion(), err)
|
||||
}
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("unsupported application payload content type: %T", typedContent)
|
||||
}
|
||||
return
|
||||
}
|
32
vendor/go.mau.fi/whatsmeow/binary/armadillo/armadilloutil/decode.go
vendored
Normal file
32
vendor/go.mau.fi/whatsmeow/binary/armadillo/armadilloutil/decode.go
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package armadilloutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waCommon"
|
||||
)
|
||||
|
||||
var ErrUnsupportedVersion = errors.New("unsupported subprotocol version")
|
||||
|
||||
func Unmarshal[T proto.Message](into T, msg *waCommon.SubProtocol, expectedVersion int32) (T, error) {
|
||||
if msg.GetVersion() != expectedVersion {
|
||||
return into, fmt.Errorf("%w %d in %T (expected %d)", ErrUnsupportedVersion, msg.GetVersion(), into, expectedVersion)
|
||||
}
|
||||
|
||||
err := proto.Unmarshal(msg.GetPayload(), into)
|
||||
return into, err
|
||||
}
|
||||
|
||||
func Marshal[T proto.Message](msg T, version int32) (*waCommon.SubProtocol, error) {
|
||||
payload, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &waCommon.SubProtocol{
|
||||
Payload: payload,
|
||||
Version: version,
|
||||
}, nil
|
||||
}
|
29
vendor/go.mau.fi/whatsmeow/binary/armadillo/extra.go
vendored
Normal file
29
vendor/go.mau.fi/whatsmeow/binary/armadillo/extra.go
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
package armadillo
|
||||
|
||||
import (
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waCommon"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMultiDevice"
|
||||
)
|
||||
|
||||
type MessageApplicationSub interface {
|
||||
IsMessageApplicationSub()
|
||||
}
|
||||
|
||||
type Unsupported_BusinessApplication waCommon.SubProtocol
|
||||
type Unsupported_PaymentApplication waCommon.SubProtocol
|
||||
type Unsupported_Voip waCommon.SubProtocol
|
||||
|
||||
var (
|
||||
_ MessageApplicationSub = (*waConsumerApplication.ConsumerApplication)(nil) // 2
|
||||
_ MessageApplicationSub = (*Unsupported_BusinessApplication)(nil) // 3
|
||||
_ MessageApplicationSub = (*Unsupported_PaymentApplication)(nil) // 4
|
||||
_ MessageApplicationSub = (*waMultiDevice.MultiDevice)(nil) // 5
|
||||
_ MessageApplicationSub = (*Unsupported_Voip)(nil) // 6
|
||||
_ MessageApplicationSub = (*waArmadilloApplication.Armadillo)(nil) // 7
|
||||
)
|
||||
|
||||
func (*Unsupported_BusinessApplication) IsMessageApplicationSub() {}
|
||||
func (*Unsupported_PaymentApplication) IsMessageApplicationSub() {}
|
||||
func (*Unsupported_Voip) IsMessageApplicationSub() {}
|
9
vendor/go.mau.fi/whatsmeow/binary/armadillo/generate.sh
vendored
Normal file
9
vendor/go.mau.fi/whatsmeow/binary/armadillo/generate.sh
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
cd $(dirname $0)
|
||||
set -euo pipefail
|
||||
if [[ ! -f "e2ee.js" ]]; then
|
||||
echo "Please download the encryption javascript file and save it to e2ee.js first"
|
||||
exit 1
|
||||
fi
|
||||
node parse-proto.js
|
||||
protoc --go_out=. --go_opt=paths=source_relative --go_opt=embed_raw=true */*.proto
|
351
vendor/go.mau.fi/whatsmeow/binary/armadillo/parse-proto.js
vendored
Normal file
351
vendor/go.mau.fi/whatsmeow/binary/armadillo/parse-proto.js
vendored
Normal file
@ -0,0 +1,351 @@
|
||||
///////////////////
|
||||
// JS EVALUATION //
|
||||
///////////////////
|
||||
|
||||
const protos = []
|
||||
const modules = {
|
||||
"$InternalEnum": {
|
||||
exports: {
|
||||
exports: function (data) {
|
||||
data.__enum__ = true
|
||||
return data
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
function requireModule(name) {
|
||||
if (!modules[name]) {
|
||||
throw new Error(`Unknown requirement ${name}`)
|
||||
}
|
||||
return modules[name].exports
|
||||
}
|
||||
|
||||
function requireDefault(name) {
|
||||
return requireModule(name).exports
|
||||
}
|
||||
|
||||
function ignoreModule(name) {
|
||||
if (name === "WAProtoConst") {
|
||||
return false
|
||||
} else if (!name.endsWith(".pb")) {
|
||||
// Ignore any non-protobuf modules, except WAProtoConst above
|
||||
return true
|
||||
} else if (name.startsWith("MAWArmadillo") && (name.endsWith("TableSchema.pb") || name.endsWith("TablesSchema.pb"))) {
|
||||
// Ignore internal table schemas
|
||||
return true
|
||||
} else if (name === "WASignalLocalStorageProtocol.pb" || name === "WASignalWhisperTextProtocol.pb") {
|
||||
// Ignore standard signal protocol stuff
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function defineModule(name, dependencies, callback, unknownIntOrNull) {
|
||||
if (ignoreModule(name)) {
|
||||
return
|
||||
}
|
||||
const exports = {}
|
||||
if (dependencies.length > 0) {
|
||||
callback(null, requireDefault, null, requireModule, null, null, exports)
|
||||
} else {
|
||||
callback(null, requireDefault, null, requireModule, exports, exports)
|
||||
}
|
||||
modules[name] = {exports, dependencies}
|
||||
}
|
||||
|
||||
global.self = global
|
||||
global.__d = defineModule
|
||||
|
||||
require("./e2ee.js")
|
||||
|
||||
function dereference(obj, module, currentPath, next, ...remainder) {
|
||||
if (!next) {
|
||||
return obj
|
||||
}
|
||||
if (!obj.messages[next]) {
|
||||
obj.messages[next] = {messages: {}, enums: {}, __module__: module, __path__: currentPath, __name__: next}
|
||||
}
|
||||
return dereference(obj.messages[next], module, currentPath.concat([next]), ...remainder)
|
||||
}
|
||||
|
||||
function dereferenceSnake(obj, currentPath, path) {
|
||||
let next = path[0]
|
||||
path = path.slice(1)
|
||||
while (!obj.messages[next]) {
|
||||
if (path.length === 0) {
|
||||
return [obj, currentPath, next]
|
||||
}
|
||||
next += path[0]
|
||||
path = path.slice(1)
|
||||
}
|
||||
return dereferenceSnake(obj.messages[next], currentPath.concat([next]), path)
|
||||
}
|
||||
|
||||
function renameModule(name) {
|
||||
return name.replace(".pb", "")
|
||||
}
|
||||
|
||||
function renameDependencies(dependencies) {
|
||||
return dependencies
|
||||
.filter(name => name.endsWith(".pb"))
|
||||
.map(renameModule)
|
||||
.map(name => name === "WAProtocol" ? "WACommon" : name)
|
||||
}
|
||||
|
||||
function renameType(protoName, fieldName, field) {
|
||||
return fieldName
|
||||
}
|
||||
|
||||
for (const [name, module] of Object.entries(modules)) {
|
||||
if (!name.endsWith(".pb")) {
|
||||
continue
|
||||
} else if (!module.exports) {
|
||||
console.warn(name, "has no exports")
|
||||
continue
|
||||
}
|
||||
// Slightly hacky way to get rid of WAProtocol.pb and just use the MessageKey in WACommon
|
||||
if (name === "WAProtocol.pb") {
|
||||
if (Object.entries(module.exports).length > 1) {
|
||||
console.warn("WAProtocol.pb has more than one export")
|
||||
}
|
||||
module.exports["MessageKeySpec"].__name__ = "MessageKey"
|
||||
module.exports["MessageKeySpec"].__module__ = "WACommon"
|
||||
module.exports["MessageKeySpec"].__path__ = []
|
||||
continue
|
||||
}
|
||||
const proto = {
|
||||
__protobuf__: true,
|
||||
messages: {},
|
||||
enums: {},
|
||||
__name__: renameModule(name),
|
||||
dependencies: renameDependencies(module.dependencies),
|
||||
}
|
||||
const upperSnakeEnums = []
|
||||
for (const [name, field] of Object.entries(module.exports)) {
|
||||
const namePath = name.replace(/Spec$/, "").split("$")
|
||||
field.__name__ = renameType(proto.__name__, namePath[namePath.length - 1], field)
|
||||
namePath[namePath.length - 1] = field.__name__
|
||||
field.__path__ = namePath.slice(0, -1)
|
||||
field.__module__ = proto.__name__
|
||||
if (field.internalSpec) {
|
||||
dereference(proto, proto.__name__, [], ...namePath).message = field.internalSpec
|
||||
} else if (namePath.length === 1 && name.toUpperCase() === name) {
|
||||
upperSnakeEnums.push(field)
|
||||
} else {
|
||||
dereference(proto, proto.__name__, [], ...namePath.slice(0, -1)).enums[field.__name__] = field
|
||||
}
|
||||
}
|
||||
// Some enums have uppercase names, instead of capital case with $ separators.
|
||||
// For those, we need to find the right nesting location.
|
||||
for (const field of upperSnakeEnums) {
|
||||
field.__enum__ = true
|
||||
const [obj, path, name] = dereferenceSnake(proto, [], field.__name__.split("_").map(part => part[0] + part.slice(1).toLowerCase()))
|
||||
field.__path__ = path
|
||||
field.__name__ = name
|
||||
field.__module__ = proto.__name__
|
||||
obj.enums[name] = field
|
||||
}
|
||||
protos.push(proto)
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// PROTOBUF SCHEMA GENERATION //
|
||||
////////////////////////////////
|
||||
|
||||
function indent(lines, indent = "\t") {
|
||||
return lines.map(line => line ? `${indent}${line}` : "")
|
||||
}
|
||||
|
||||
function flattenWithBlankLines(...items) {
|
||||
return items
|
||||
.flatMap(item => item.length > 0 ? [item, [""]] : [])
|
||||
.slice(0, -1)
|
||||
.flatMap(item => item)
|
||||
}
|
||||
|
||||
function protoifyChildren(container) {
|
||||
return flattenWithBlankLines(
|
||||
...Object.values(container.enums).map(protoifyEnum),
|
||||
...Object.values(container.messages).map(protoifyMessage),
|
||||
)
|
||||
}
|
||||
|
||||
function protoifyEnum(enumDef) {
|
||||
const values = []
|
||||
const names = Object.fromEntries(Object.entries(enumDef).map(([name, value]) => [value, name]))
|
||||
if (!names["0"]) {
|
||||
if (names["-1"]) {
|
||||
enumDef[names["-1"]] = 0
|
||||
} else {
|
||||
// TODO add snake case
|
||||
values.push(`${enumDef.__name__.toUpperCase()}_UNKNOWN = 0;`)
|
||||
}
|
||||
}
|
||||
for (const [name, value] of Object.entries(enumDef)) {
|
||||
if (name.startsWith("__") && name.endsWith("__")) {
|
||||
continue
|
||||
}
|
||||
values.push(`${name} = ${value};`)
|
||||
}
|
||||
return [`enum ${enumDef.__name__} ` + "{", ...indent(values), "}"]
|
||||
}
|
||||
|
||||
const {TYPES, TYPE_MASK, FLAGS} = requireModule("WAProtoConst")
|
||||
|
||||
function fieldTypeName(typeID, typeRef, parentModule, parentPath) {
|
||||
switch (typeID) {
|
||||
case TYPES.INT32:
|
||||
return "int32"
|
||||
case TYPES.INT64:
|
||||
return "int64"
|
||||
case TYPES.UINT32:
|
||||
return "uint32"
|
||||
case TYPES.UINT64:
|
||||
return "uint64"
|
||||
case TYPES.SINT32:
|
||||
return "sint32"
|
||||
case TYPES.SINT64:
|
||||
return "sint64"
|
||||
case TYPES.BOOL:
|
||||
return "bool"
|
||||
case TYPES.ENUM:
|
||||
case TYPES.MESSAGE:
|
||||
let pathStartIndex = 0
|
||||
for (let i = 0; i < parentPath.length && i < typeRef.__path__.length; i++) {
|
||||
if (typeRef.__path__[i] === parentPath[i]) {
|
||||
pathStartIndex++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
const namePath = []
|
||||
if (typeRef.__module__ !== parentModule) {
|
||||
namePath.push(typeRef.__module__)
|
||||
pathStartIndex = 0
|
||||
}
|
||||
namePath.push(...typeRef.__path__.slice(pathStartIndex))
|
||||
namePath.push(typeRef.__name__)
|
||||
return namePath.join(".")
|
||||
case TYPES.FIXED64:
|
||||
return "fixed64"
|
||||
case TYPES.SFIXED64:
|
||||
return "sfixed64"
|
||||
case TYPES.DOUBLE:
|
||||
return "double"
|
||||
case TYPES.STRING:
|
||||
return "string"
|
||||
case TYPES.BYTES:
|
||||
return "bytes"
|
||||
case TYPES.FIXED32:
|
||||
return "fixed32"
|
||||
case TYPES.SFIXED32:
|
||||
return "sfixed32"
|
||||
case TYPES.FLOAT:
|
||||
return "float"
|
||||
}
|
||||
}
|
||||
|
||||
const staticRenames = {
|
||||
id: "ID",
|
||||
jid: "JID",
|
||||
encIv: "encIV",
|
||||
iv: "IV",
|
||||
ptt: "PTT",
|
||||
hmac: "HMAC",
|
||||
url: "URL",
|
||||
fbid: "FBID",
|
||||
jpegThumbnail: "JPEGThumbnail",
|
||||
dsm: "DSM",
|
||||
}
|
||||
|
||||
function fixFieldName(name) {
|
||||
if (name === "id") {
|
||||
return "ID"
|
||||
} else if (name === "encIv") {
|
||||
return "encIV"
|
||||
}
|
||||
return staticRenames[name] ?? name
|
||||
.replace(/Id([A-Zs]|$)/, "ID$1")
|
||||
.replace("Jid", "JID")
|
||||
.replace(/Ms([A-Z]|$)/, "MS$1")
|
||||
.replace(/Ts([A-Z]|$)/, "TS$1")
|
||||
.replace(/Mac([A-Z]|$)/, "MAC$1")
|
||||
.replace("Url", "URL")
|
||||
.replace("Cdn", "CDN")
|
||||
.replace("Json", "JSON")
|
||||
.replace("Jpeg", "JPEG")
|
||||
.replace("Sha256", "SHA256")
|
||||
}
|
||||
|
||||
function protoifyField(name, [index, flags, typeRef], parentModule, parentPath) {
|
||||
const preflags = []
|
||||
const postflags = [""]
|
||||
if ((flags & FLAGS.REPEATED) !== 0) {
|
||||
preflags.push("repeated")
|
||||
}
|
||||
// if ((flags & FLAGS.REQUIRED) === 0) {
|
||||
// preflags.push("optional")
|
||||
// } else {
|
||||
// preflags.push("required")
|
||||
// }
|
||||
preflags.push(fieldTypeName(flags & TYPE_MASK, typeRef, parentModule, parentPath))
|
||||
if ((flags & FLAGS.PACKED) !== 0) {
|
||||
postflags.push(`[packed=true]`)
|
||||
}
|
||||
return `${preflags.join(" ")} ${fixFieldName(name)} = ${index}${postflags.join(" ")};`
|
||||
}
|
||||
|
||||
function protoifyFields(fields, parentModule, parentPath) {
|
||||
return Object.entries(fields).map(([name, definition]) => protoifyField(name, definition, parentModule, parentPath))
|
||||
}
|
||||
|
||||
function protoifyMessage(message) {
|
||||
const sections = [protoifyChildren(message)]
|
||||
const spec = message.message
|
||||
const fullMessagePath = message.__path__.concat([message.__name__])
|
||||
for (const [name, fieldNames] of Object.entries(spec.__oneofs__ ?? {})) {
|
||||
const fields = Object.fromEntries(fieldNames.map(fieldName => {
|
||||
const def = spec[fieldName]
|
||||
delete spec[fieldName]
|
||||
return [fieldName, def]
|
||||
}))
|
||||
sections.push([`oneof ${name} ` + "{", ...indent(protoifyFields(fields, message.__module__, fullMessagePath)), "}"])
|
||||
}
|
||||
if (spec.__reserved__) {
|
||||
console.warn("Found reserved keys:", message.__name__, spec.__reserved__)
|
||||
}
|
||||
delete spec.__oneofs__
|
||||
delete spec.__reserved__
|
||||
sections.push(protoifyFields(spec, message.__module__, fullMessagePath))
|
||||
return [`message ${message.__name__} ` + "{", ...indent(flattenWithBlankLines(...sections)), "}"]
|
||||
}
|
||||
|
||||
function goPackageName(name) {
|
||||
return name.replace(/^WA/, "wa")
|
||||
}
|
||||
|
||||
function protoifyModule(module) {
|
||||
const output = []
|
||||
output.push(`syntax = "proto3";`)
|
||||
output.push(`package ${module.__name__};`)
|
||||
output.push(`option go_package = "go.mau.fi/whatsmeow/binary/armadillo/${goPackageName(module.__name__)}";`)
|
||||
output.push("")
|
||||
if (module.dependencies.length > 0) {
|
||||
for (const dependency of module.dependencies) {
|
||||
output.push(`import "${goPackageName(dependency)}/${dependency}.proto";`)
|
||||
}
|
||||
output.push("")
|
||||
}
|
||||
const children = protoifyChildren(module)
|
||||
children.push("")
|
||||
return output.concat(children)
|
||||
}
|
||||
|
||||
const fs = require("fs")
|
||||
|
||||
for (const proto of protos) {
|
||||
fs.mkdirSync(goPackageName(proto.__name__), {recursive: true})
|
||||
fs.writeFileSync(`${goPackageName(proto.__name__)}/${proto.__name__}.proto`, protoifyModule(proto).join("\n"))
|
||||
}
|
552
vendor/go.mau.fi/whatsmeow/binary/armadillo/waAdv/WAAdv.pb.go
vendored
Normal file
552
vendor/go.mau.fi/whatsmeow/binary/armadillo/waAdv/WAAdv.pb.go
vendored
Normal file
@ -0,0 +1,552 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v3.21.12
|
||||
// source: waAdv/WAAdv.proto
|
||||
|
||||
package waAdv
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ADVEncryptionType int32
|
||||
|
||||
const (
|
||||
ADVEncryptionType_E2EE ADVEncryptionType = 0
|
||||
ADVEncryptionType_HOSTED ADVEncryptionType = 1
|
||||
)
|
||||
|
||||
// Enum value maps for ADVEncryptionType.
|
||||
var (
|
||||
ADVEncryptionType_name = map[int32]string{
|
||||
0: "E2EE",
|
||||
1: "HOSTED",
|
||||
}
|
||||
ADVEncryptionType_value = map[string]int32{
|
||||
"E2EE": 0,
|
||||
"HOSTED": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ADVEncryptionType) Enum() *ADVEncryptionType {
|
||||
p := new(ADVEncryptionType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ADVEncryptionType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ADVEncryptionType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_waAdv_WAAdv_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (ADVEncryptionType) Type() protoreflect.EnumType {
|
||||
return &file_waAdv_WAAdv_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x ADVEncryptionType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ADVEncryptionType.Descriptor instead.
|
||||
func (ADVEncryptionType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type ADVKeyIndexList struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
RawID uint32 `protobuf:"varint,1,opt,name=rawID,proto3" json:"rawID,omitempty"`
|
||||
Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
CurrentIndex uint32 `protobuf:"varint,3,opt,name=currentIndex,proto3" json:"currentIndex,omitempty"`
|
||||
ValidIndexes []uint32 `protobuf:"varint,4,rep,packed,name=validIndexes,proto3" json:"validIndexes,omitempty"`
|
||||
AccountType ADVEncryptionType `protobuf:"varint,5,opt,name=accountType,proto3,enum=WAAdv.ADVEncryptionType" json:"accountType,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ADVKeyIndexList) Reset() {
|
||||
*x = ADVKeyIndexList{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ADVKeyIndexList) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ADVKeyIndexList) ProtoMessage() {}
|
||||
|
||||
func (x *ADVKeyIndexList) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ADVKeyIndexList.ProtoReflect.Descriptor instead.
|
||||
func (*ADVKeyIndexList) Descriptor() ([]byte, []int) {
|
||||
return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ADVKeyIndexList) GetRawID() uint32 {
|
||||
if x != nil {
|
||||
return x.RawID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ADVKeyIndexList) GetTimestamp() uint64 {
|
||||
if x != nil {
|
||||
return x.Timestamp
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ADVKeyIndexList) GetCurrentIndex() uint32 {
|
||||
if x != nil {
|
||||
return x.CurrentIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ADVKeyIndexList) GetValidIndexes() []uint32 {
|
||||
if x != nil {
|
||||
return x.ValidIndexes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ADVKeyIndexList) GetAccountType() ADVEncryptionType {
|
||||
if x != nil {
|
||||
return x.AccountType
|
||||
}
|
||||
return ADVEncryptionType_E2EE
|
||||
}
|
||||
|
||||
type ADVSignedKeyIndexList struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Details []byte `protobuf:"bytes,1,opt,name=details,proto3" json:"details,omitempty"`
|
||||
AccountSignature []byte `protobuf:"bytes,2,opt,name=accountSignature,proto3" json:"accountSignature,omitempty"`
|
||||
AccountSignatureKey []byte `protobuf:"bytes,3,opt,name=accountSignatureKey,proto3" json:"accountSignatureKey,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ADVSignedKeyIndexList) Reset() {
|
||||
*x = ADVSignedKeyIndexList{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ADVSignedKeyIndexList) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ADVSignedKeyIndexList) ProtoMessage() {}
|
||||
|
||||
func (x *ADVSignedKeyIndexList) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ADVSignedKeyIndexList.ProtoReflect.Descriptor instead.
|
||||
func (*ADVSignedKeyIndexList) Descriptor() ([]byte, []int) {
|
||||
return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *ADVSignedKeyIndexList) GetDetails() []byte {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ADVSignedKeyIndexList) GetAccountSignature() []byte {
|
||||
if x != nil {
|
||||
return x.AccountSignature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ADVSignedKeyIndexList) GetAccountSignatureKey() []byte {
|
||||
if x != nil {
|
||||
return x.AccountSignatureKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ADVDeviceIdentity struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
RawID uint32 `protobuf:"varint,1,opt,name=rawID,proto3" json:"rawID,omitempty"`
|
||||
Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
KeyIndex uint32 `protobuf:"varint,3,opt,name=keyIndex,proto3" json:"keyIndex,omitempty"`
|
||||
AccountType ADVEncryptionType `protobuf:"varint,4,opt,name=accountType,proto3,enum=WAAdv.ADVEncryptionType" json:"accountType,omitempty"`
|
||||
DeviceType ADVEncryptionType `protobuf:"varint,5,opt,name=deviceType,proto3,enum=WAAdv.ADVEncryptionType" json:"deviceType,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ADVDeviceIdentity) Reset() {
|
||||
*x = ADVDeviceIdentity{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ADVDeviceIdentity) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ADVDeviceIdentity) ProtoMessage() {}
|
||||
|
||||
func (x *ADVDeviceIdentity) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ADVDeviceIdentity.ProtoReflect.Descriptor instead.
|
||||
func (*ADVDeviceIdentity) Descriptor() ([]byte, []int) {
|
||||
return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *ADVDeviceIdentity) GetRawID() uint32 {
|
||||
if x != nil {
|
||||
return x.RawID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ADVDeviceIdentity) GetTimestamp() uint64 {
|
||||
if x != nil {
|
||||
return x.Timestamp
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ADVDeviceIdentity) GetKeyIndex() uint32 {
|
||||
if x != nil {
|
||||
return x.KeyIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ADVDeviceIdentity) GetAccountType() ADVEncryptionType {
|
||||
if x != nil {
|
||||
return x.AccountType
|
||||
}
|
||||
return ADVEncryptionType_E2EE
|
||||
}
|
||||
|
||||
func (x *ADVDeviceIdentity) GetDeviceType() ADVEncryptionType {
|
||||
if x != nil {
|
||||
return x.DeviceType
|
||||
}
|
||||
return ADVEncryptionType_E2EE
|
||||
}
|
||||
|
||||
type ADVSignedDeviceIdentity struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Details []byte `protobuf:"bytes,1,opt,name=details,proto3" json:"details,omitempty"`
|
||||
AccountSignatureKey []byte `protobuf:"bytes,2,opt,name=accountSignatureKey,proto3" json:"accountSignatureKey,omitempty"`
|
||||
AccountSignature []byte `protobuf:"bytes,3,opt,name=accountSignature,proto3" json:"accountSignature,omitempty"`
|
||||
DeviceSignature []byte `protobuf:"bytes,4,opt,name=deviceSignature,proto3" json:"deviceSignature,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentity) Reset() {
|
||||
*x = ADVSignedDeviceIdentity{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentity) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ADVSignedDeviceIdentity) ProtoMessage() {}
|
||||
|
||||
func (x *ADVSignedDeviceIdentity) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ADVSignedDeviceIdentity.ProtoReflect.Descriptor instead.
|
||||
func (*ADVSignedDeviceIdentity) Descriptor() ([]byte, []int) {
|
||||
return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentity) GetDetails() []byte {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentity) GetAccountSignatureKey() []byte {
|
||||
if x != nil {
|
||||
return x.AccountSignatureKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentity) GetAccountSignature() []byte {
|
||||
if x != nil {
|
||||
return x.AccountSignature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentity) GetDeviceSignature() []byte {
|
||||
if x != nil {
|
||||
return x.DeviceSignature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ADVSignedDeviceIdentityHMAC struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Details []byte `protobuf:"bytes,1,opt,name=details,proto3" json:"details,omitempty"`
|
||||
HMAC []byte `protobuf:"bytes,2,opt,name=HMAC,proto3" json:"HMAC,omitempty"`
|
||||
AccountType ADVEncryptionType `protobuf:"varint,3,opt,name=accountType,proto3,enum=WAAdv.ADVEncryptionType" json:"accountType,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentityHMAC) Reset() {
|
||||
*x = ADVSignedDeviceIdentityHMAC{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentityHMAC) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ADVSignedDeviceIdentityHMAC) ProtoMessage() {}
|
||||
|
||||
func (x *ADVSignedDeviceIdentityHMAC) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waAdv_WAAdv_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ADVSignedDeviceIdentityHMAC.ProtoReflect.Descriptor instead.
|
||||
func (*ADVSignedDeviceIdentityHMAC) Descriptor() ([]byte, []int) {
|
||||
return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentityHMAC) GetDetails() []byte {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentityHMAC) GetHMAC() []byte {
|
||||
if x != nil {
|
||||
return x.HMAC
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ADVSignedDeviceIdentityHMAC) GetAccountType() ADVEncryptionType {
|
||||
if x != nil {
|
||||
return x.AccountType
|
||||
}
|
||||
return ADVEncryptionType_E2EE
|
||||
}
|
||||
|
||||
var File_waAdv_WAAdv_proto protoreflect.FileDescriptor
|
||||
|
||||
//go:embed WAAdv.pb.raw
|
||||
var file_waAdv_WAAdv_proto_rawDesc []byte
|
||||
|
||||
var (
|
||||
file_waAdv_WAAdv_proto_rawDescOnce sync.Once
|
||||
file_waAdv_WAAdv_proto_rawDescData = file_waAdv_WAAdv_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_waAdv_WAAdv_proto_rawDescGZIP() []byte {
|
||||
file_waAdv_WAAdv_proto_rawDescOnce.Do(func() {
|
||||
file_waAdv_WAAdv_proto_rawDescData = protoimpl.X.CompressGZIP(file_waAdv_WAAdv_proto_rawDescData)
|
||||
})
|
||||
return file_waAdv_WAAdv_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_waAdv_WAAdv_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_waAdv_WAAdv_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_waAdv_WAAdv_proto_goTypes = []interface{}{
|
||||
(ADVEncryptionType)(0), // 0: WAAdv.ADVEncryptionType
|
||||
(*ADVKeyIndexList)(nil), // 1: WAAdv.ADVKeyIndexList
|
||||
(*ADVSignedKeyIndexList)(nil), // 2: WAAdv.ADVSignedKeyIndexList
|
||||
(*ADVDeviceIdentity)(nil), // 3: WAAdv.ADVDeviceIdentity
|
||||
(*ADVSignedDeviceIdentity)(nil), // 4: WAAdv.ADVSignedDeviceIdentity
|
||||
(*ADVSignedDeviceIdentityHMAC)(nil), // 5: WAAdv.ADVSignedDeviceIdentityHMAC
|
||||
}
|
||||
var file_waAdv_WAAdv_proto_depIdxs = []int32{
|
||||
0, // 0: WAAdv.ADVKeyIndexList.accountType:type_name -> WAAdv.ADVEncryptionType
|
||||
0, // 1: WAAdv.ADVDeviceIdentity.accountType:type_name -> WAAdv.ADVEncryptionType
|
||||
0, // 2: WAAdv.ADVDeviceIdentity.deviceType:type_name -> WAAdv.ADVEncryptionType
|
||||
0, // 3: WAAdv.ADVSignedDeviceIdentityHMAC.accountType:type_name -> WAAdv.ADVEncryptionType
|
||||
4, // [4:4] is the sub-list for method output_type
|
||||
4, // [4:4] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_waAdv_WAAdv_proto_init() }
|
||||
func file_waAdv_WAAdv_proto_init() {
|
||||
if File_waAdv_WAAdv_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_waAdv_WAAdv_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ADVKeyIndexList); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waAdv_WAAdv_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ADVSignedKeyIndexList); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waAdv_WAAdv_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ADVDeviceIdentity); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waAdv_WAAdv_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ADVSignedDeviceIdentity); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waAdv_WAAdv_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ADVSignedDeviceIdentityHMAC); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_waAdv_WAAdv_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_waAdv_WAAdv_proto_goTypes,
|
||||
DependencyIndexes: file_waAdv_WAAdv_proto_depIdxs,
|
||||
EnumInfos: file_waAdv_WAAdv_proto_enumTypes,
|
||||
MessageInfos: file_waAdv_WAAdv_proto_msgTypes,
|
||||
}.Build()
|
||||
File_waAdv_WAAdv_proto = out.File
|
||||
file_waAdv_WAAdv_proto_rawDesc = nil
|
||||
file_waAdv_WAAdv_proto_goTypes = nil
|
||||
file_waAdv_WAAdv_proto_depIdxs = nil
|
||||
}
|
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waAdv/WAAdv.pb.raw
vendored
Normal file
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waAdv/WAAdv.pb.raw
vendored
Normal file
Binary file not shown.
43
vendor/go.mau.fi/whatsmeow/binary/armadillo/waAdv/WAAdv.proto
vendored
Normal file
43
vendor/go.mau.fi/whatsmeow/binary/armadillo/waAdv/WAAdv.proto
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
syntax = "proto3";
|
||||
package WAAdv;
|
||||
option go_package = "go.mau.fi/whatsmeow/binary/armadillo/waAdv";
|
||||
|
||||
enum ADVEncryptionType {
|
||||
E2EE = 0;
|
||||
HOSTED = 1;
|
||||
}
|
||||
|
||||
message ADVKeyIndexList {
|
||||
uint32 rawID = 1;
|
||||
uint64 timestamp = 2;
|
||||
uint32 currentIndex = 3;
|
||||
repeated uint32 validIndexes = 4 [packed=true];
|
||||
ADVEncryptionType accountType = 5;
|
||||
}
|
||||
|
||||
message ADVSignedKeyIndexList {
|
||||
bytes details = 1;
|
||||
bytes accountSignature = 2;
|
||||
bytes accountSignatureKey = 3;
|
||||
}
|
||||
|
||||
message ADVDeviceIdentity {
|
||||
uint32 rawID = 1;
|
||||
uint64 timestamp = 2;
|
||||
uint32 keyIndex = 3;
|
||||
ADVEncryptionType accountType = 4;
|
||||
ADVEncryptionType deviceType = 5;
|
||||
}
|
||||
|
||||
message ADVSignedDeviceIdentity {
|
||||
bytes details = 1;
|
||||
bytes accountSignatureKey = 2;
|
||||
bytes accountSignature = 3;
|
||||
bytes deviceSignature = 4;
|
||||
}
|
||||
|
||||
message ADVSignedDeviceIdentityHMAC {
|
||||
bytes details = 1;
|
||||
bytes HMAC = 2;
|
||||
ADVEncryptionType accountType = 3;
|
||||
}
|
2927
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication/WAArmadilloApplication.pb.go
vendored
Normal file
2927
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication/WAArmadilloApplication.pb.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication/WAArmadilloApplication.pb.raw
vendored
Normal file
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication/WAArmadilloApplication.pb.raw
vendored
Normal file
Binary file not shown.
245
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication/WAArmadilloApplication.proto
vendored
Normal file
245
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication/WAArmadilloApplication.proto
vendored
Normal file
@ -0,0 +1,245 @@
|
||||
syntax = "proto3";
|
||||
package WAArmadilloApplication;
|
||||
option go_package = "go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication";
|
||||
|
||||
import "waArmadilloXMA/WAArmadilloXMA.proto";
|
||||
import "waCommon/WACommon.proto";
|
||||
|
||||
message Armadillo {
|
||||
message Metadata {
|
||||
}
|
||||
|
||||
message Payload {
|
||||
oneof payload {
|
||||
Content content = 1;
|
||||
ApplicationData applicationData = 2;
|
||||
Signal signal = 3;
|
||||
SubProtocolPayload subProtocol = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message SubProtocolPayload {
|
||||
WACommon.FutureProofBehavior futureProof = 1;
|
||||
}
|
||||
|
||||
message Signal {
|
||||
message EncryptedBackupsSecrets {
|
||||
message Epoch {
|
||||
enum EpochStatus {
|
||||
EPOCHSTATUS_UNKNOWN = 0;
|
||||
ES_OPEN = 1;
|
||||
ES_CLOSE = 2;
|
||||
}
|
||||
|
||||
uint64 ID = 1;
|
||||
bytes anonID = 2;
|
||||
bytes rootKey = 3;
|
||||
EpochStatus status = 4;
|
||||
}
|
||||
|
||||
uint64 backupID = 1;
|
||||
uint64 serverDataID = 2;
|
||||
repeated Epoch epoch = 3;
|
||||
bytes tempOcmfClientState = 4;
|
||||
bytes mailboxRootKey = 5;
|
||||
bytes obliviousValidationToken = 6;
|
||||
}
|
||||
|
||||
oneof signal {
|
||||
EncryptedBackupsSecrets encryptedBackupsSecrets = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message ApplicationData {
|
||||
message AIBotResponseMessage {
|
||||
string summonToken = 1;
|
||||
string messageText = 2;
|
||||
string serializedExtras = 3;
|
||||
}
|
||||
|
||||
message MetadataSyncAction {
|
||||
message SyncMessageAction {
|
||||
message ActionMessageDelete {
|
||||
}
|
||||
|
||||
oneof action {
|
||||
ActionMessageDelete messageDelete = 101;
|
||||
}
|
||||
|
||||
WACommon.MessageKey key = 1;
|
||||
}
|
||||
|
||||
message SyncChatAction {
|
||||
message ActionChatRead {
|
||||
SyncActionMessageRange messageRange = 1;
|
||||
bool read = 2;
|
||||
}
|
||||
|
||||
message ActionChatDelete {
|
||||
SyncActionMessageRange messageRange = 1;
|
||||
}
|
||||
|
||||
message ActionChatArchive {
|
||||
SyncActionMessageRange messageRange = 1;
|
||||
bool archived = 2;
|
||||
}
|
||||
|
||||
oneof action {
|
||||
ActionChatArchive chatArchive = 101;
|
||||
ActionChatDelete chatDelete = 102;
|
||||
ActionChatRead chatRead = 103;
|
||||
}
|
||||
|
||||
string chatID = 1;
|
||||
}
|
||||
|
||||
message SyncActionMessage {
|
||||
WACommon.MessageKey key = 1;
|
||||
int64 timestamp = 2;
|
||||
}
|
||||
|
||||
message SyncActionMessageRange {
|
||||
int64 lastMessageTimestamp = 1;
|
||||
int64 lastSystemMessageTimestamp = 2;
|
||||
repeated SyncActionMessage messages = 3;
|
||||
}
|
||||
|
||||
oneof actionType {
|
||||
SyncChatAction chatAction = 101;
|
||||
SyncMessageAction messageAction = 102;
|
||||
}
|
||||
|
||||
int64 actionTimestamp = 1;
|
||||
}
|
||||
|
||||
message MetadataSyncNotification {
|
||||
repeated MetadataSyncAction actions = 2;
|
||||
}
|
||||
|
||||
oneof applicationData {
|
||||
MetadataSyncNotification metadataSync = 1;
|
||||
AIBotResponseMessage aiBotResponse = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message Content {
|
||||
message PaymentsTransactionMessage {
|
||||
enum PaymentStatus {
|
||||
PAYMENT_UNKNOWN = 0;
|
||||
REQUEST_INITED = 4;
|
||||
REQUEST_DECLINED = 5;
|
||||
REQUEST_TRANSFER_INITED = 6;
|
||||
REQUEST_TRANSFER_COMPLETED = 7;
|
||||
REQUEST_TRANSFER_FAILED = 8;
|
||||
REQUEST_CANCELED = 9;
|
||||
REQUEST_EXPIRED = 10;
|
||||
TRANSFER_INITED = 11;
|
||||
TRANSFER_PENDING = 12;
|
||||
TRANSFER_PENDING_RECIPIENT_VERIFICATION = 13;
|
||||
TRANSFER_CANCELED = 14;
|
||||
TRANSFER_COMPLETED = 15;
|
||||
TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_CANCELED = 16;
|
||||
TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_OTHER = 17;
|
||||
TRANSFER_REFUNDED = 18;
|
||||
TRANSFER_PARTIAL_REFUND = 19;
|
||||
TRANSFER_CHARGED_BACK = 20;
|
||||
TRANSFER_EXPIRED = 21;
|
||||
TRANSFER_DECLINED = 22;
|
||||
TRANSFER_UNAVAILABLE = 23;
|
||||
}
|
||||
|
||||
uint64 transactionID = 1;
|
||||
string amount = 2;
|
||||
string currency = 3;
|
||||
PaymentStatus paymentStatus = 4;
|
||||
WAArmadilloXMA.ExtendedContentMessage extendedContentMessage = 5;
|
||||
}
|
||||
|
||||
message NoteReplyMessage {
|
||||
string noteID = 1;
|
||||
WACommon.MessageText noteText = 2;
|
||||
int64 noteTimestampMS = 3;
|
||||
WACommon.MessageText noteReplyText = 4;
|
||||
}
|
||||
|
||||
message BumpExistingMessage {
|
||||
WACommon.MessageKey key = 1;
|
||||
}
|
||||
|
||||
message ImageGalleryMessage {
|
||||
repeated WACommon.SubProtocol images = 1;
|
||||
}
|
||||
|
||||
message ScreenshotAction {
|
||||
enum ScreenshotType {
|
||||
SCREENSHOTTYPE_UNKNOWN = 0;
|
||||
SCREENSHOT_IMAGE = 1;
|
||||
SCREEN_RECORDING = 2;
|
||||
}
|
||||
|
||||
ScreenshotType screenshotType = 1;
|
||||
}
|
||||
|
||||
message ExtendedContentMessageWithSear {
|
||||
string searID = 1;
|
||||
bytes payload = 2;
|
||||
string nativeURL = 3;
|
||||
WACommon.SubProtocol searAssociatedMessage = 4;
|
||||
string searSentWithMessageID = 5;
|
||||
}
|
||||
|
||||
message RavenActionNotifMessage {
|
||||
enum ActionType {
|
||||
PLAYED = 0;
|
||||
SCREENSHOT = 1;
|
||||
FORCE_DISABLE = 2;
|
||||
}
|
||||
|
||||
WACommon.MessageKey key = 1;
|
||||
int64 actionTimestamp = 2;
|
||||
ActionType actionType = 3;
|
||||
}
|
||||
|
||||
message RavenMessage {
|
||||
enum EphemeralType {
|
||||
VIEW_ONCE = 0;
|
||||
ALLOW_REPLAY = 1;
|
||||
KEEP_IN_CHAT = 2;
|
||||
}
|
||||
|
||||
oneof mediaContent {
|
||||
WACommon.SubProtocol imageMessage = 2;
|
||||
WACommon.SubProtocol videoMessage = 3;
|
||||
}
|
||||
|
||||
EphemeralType ephemeralType = 1;
|
||||
}
|
||||
|
||||
message CommonSticker {
|
||||
enum StickerType {
|
||||
STICKERTYPE_UNKNOWN = 0;
|
||||
SMALL_LIKE = 1;
|
||||
MEDIUM_LIKE = 2;
|
||||
LARGE_LIKE = 3;
|
||||
}
|
||||
|
||||
StickerType stickerType = 1;
|
||||
}
|
||||
|
||||
oneof content {
|
||||
CommonSticker commonSticker = 1;
|
||||
ScreenshotAction screenshotAction = 3;
|
||||
WAArmadilloXMA.ExtendedContentMessage extendedContentMessage = 4;
|
||||
RavenMessage ravenMessage = 5;
|
||||
RavenActionNotifMessage ravenActionNotifMessage = 6;
|
||||
ExtendedContentMessageWithSear extendedMessageContentWithSear = 7;
|
||||
ImageGalleryMessage imageGalleryMessage = 8;
|
||||
PaymentsTransactionMessage paymentsTransactionMessage = 10;
|
||||
BumpExistingMessage bumpExistingMessage = 11;
|
||||
NoteReplyMessage noteReplyMessage = 13;
|
||||
}
|
||||
}
|
||||
|
||||
Payload payload = 1;
|
||||
Metadata metadata = 2;
|
||||
}
|
3
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication/extra.go
vendored
Normal file
3
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloApplication/extra.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package waArmadilloApplication
|
||||
|
||||
func (*Armadillo) IsMessageApplicationSub() {}
|
317
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloBackupMessage/WAArmadilloBackupMessage.pb.go
vendored
Normal file
317
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloBackupMessage/WAArmadilloBackupMessage.pb.go
vendored
Normal file
@ -0,0 +1,317 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v3.21.12
|
||||
// source: waArmadilloBackupMessage/WAArmadilloBackupMessage.proto
|
||||
|
||||
package waArmadilloBackupMessage
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type BackupMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Metadata *BackupMessage_Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
|
||||
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BackupMessage) Reset() {
|
||||
*x = BackupMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *BackupMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BackupMessage) ProtoMessage() {}
|
||||
|
||||
func (x *BackupMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BackupMessage.ProtoReflect.Descriptor instead.
|
||||
func (*BackupMessage) Descriptor() ([]byte, []int) {
|
||||
return file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *BackupMessage) GetMetadata() *BackupMessage_Metadata {
|
||||
if x != nil {
|
||||
return x.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BackupMessage) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type BackupMessage_Metadata struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
SenderID string `protobuf:"bytes,1,opt,name=senderID,proto3" json:"senderID,omitempty"`
|
||||
MessageID string `protobuf:"bytes,2,opt,name=messageID,proto3" json:"messageID,omitempty"`
|
||||
TimestampMS int64 `protobuf:"varint,3,opt,name=timestampMS,proto3" json:"timestampMS,omitempty"`
|
||||
FrankingMetadata *BackupMessage_Metadata_FrankingMetadata `protobuf:"bytes,4,opt,name=frankingMetadata,proto3" json:"frankingMetadata,omitempty"`
|
||||
PayloadVersion int32 `protobuf:"varint,5,opt,name=payloadVersion,proto3" json:"payloadVersion,omitempty"`
|
||||
FutureProofBehavior int32 `protobuf:"varint,6,opt,name=futureProofBehavior,proto3" json:"futureProofBehavior,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata) Reset() {
|
||||
*x = BackupMessage_Metadata{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BackupMessage_Metadata) ProtoMessage() {}
|
||||
|
||||
func (x *BackupMessage_Metadata) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BackupMessage_Metadata.ProtoReflect.Descriptor instead.
|
||||
func (*BackupMessage_Metadata) Descriptor() ([]byte, []int) {
|
||||
return file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata) GetSenderID() string {
|
||||
if x != nil {
|
||||
return x.SenderID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata) GetMessageID() string {
|
||||
if x != nil {
|
||||
return x.MessageID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata) GetTimestampMS() int64 {
|
||||
if x != nil {
|
||||
return x.TimestampMS
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata) GetFrankingMetadata() *BackupMessage_Metadata_FrankingMetadata {
|
||||
if x != nil {
|
||||
return x.FrankingMetadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata) GetPayloadVersion() int32 {
|
||||
if x != nil {
|
||||
return x.PayloadVersion
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata) GetFutureProofBehavior() int32 {
|
||||
if x != nil {
|
||||
return x.FutureProofBehavior
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type BackupMessage_Metadata_FrankingMetadata struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
FrankingTag []byte `protobuf:"bytes,3,opt,name=frankingTag,proto3" json:"frankingTag,omitempty"`
|
||||
ReportingTag []byte `protobuf:"bytes,4,opt,name=reportingTag,proto3" json:"reportingTag,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata_FrankingMetadata) Reset() {
|
||||
*x = BackupMessage_Metadata_FrankingMetadata{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata_FrankingMetadata) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BackupMessage_Metadata_FrankingMetadata) ProtoMessage() {}
|
||||
|
||||
func (x *BackupMessage_Metadata_FrankingMetadata) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BackupMessage_Metadata_FrankingMetadata.ProtoReflect.Descriptor instead.
|
||||
func (*BackupMessage_Metadata_FrankingMetadata) Descriptor() ([]byte, []int) {
|
||||
return file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescGZIP(), []int{0, 0, 0}
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata_FrankingMetadata) GetFrankingTag() []byte {
|
||||
if x != nil {
|
||||
return x.FrankingTag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BackupMessage_Metadata_FrankingMetadata) GetReportingTag() []byte {
|
||||
if x != nil {
|
||||
return x.ReportingTag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto protoreflect.FileDescriptor
|
||||
|
||||
//go:embed WAArmadilloBackupMessage.pb.raw
|
||||
var file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc []byte
|
||||
|
||||
var (
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescOnce sync.Once
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescData = file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescGZIP() []byte {
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescOnce.Do(func() {
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescData = protoimpl.X.CompressGZIP(file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescData)
|
||||
})
|
||||
return file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_goTypes = []interface{}{
|
||||
(*BackupMessage)(nil), // 0: WAArmadilloBackupMessage.BackupMessage
|
||||
(*BackupMessage_Metadata)(nil), // 1: WAArmadilloBackupMessage.BackupMessage.Metadata
|
||||
(*BackupMessage_Metadata_FrankingMetadata)(nil), // 2: WAArmadilloBackupMessage.BackupMessage.Metadata.FrankingMetadata
|
||||
}
|
||||
var file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_depIdxs = []int32{
|
||||
1, // 0: WAArmadilloBackupMessage.BackupMessage.metadata:type_name -> WAArmadilloBackupMessage.BackupMessage.Metadata
|
||||
2, // 1: WAArmadilloBackupMessage.BackupMessage.Metadata.frankingMetadata:type_name -> WAArmadilloBackupMessage.BackupMessage.Metadata.FrankingMetadata
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_init() }
|
||||
func file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_init() {
|
||||
if File_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*BackupMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*BackupMessage_Metadata); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*BackupMessage_Metadata_FrankingMetadata); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_goTypes,
|
||||
DependencyIndexes: file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_depIdxs,
|
||||
MessageInfos: file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes,
|
||||
}.Build()
|
||||
File_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto = out.File
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc = nil
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_goTypes = nil
|
||||
file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_depIdxs = nil
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
|
||||
7waArmadilloBackupMessage/WAArmadilloBackupMessage.protoWAArmadilloBackupMessage"ƒ
|
||||
BackupMessageL
|
||||
metadata (20.WAArmadilloBackupMessage.BackupMessage.MetadataRmetadata
|
||||
payload (Rpayload‰
|
||||
Metadata
|
||||
senderID ( RsenderID
|
||||
messageID ( R messageID
|
||||
timestampMS (RtimestampMSm
|
||||
frankingMetadata (2A.WAArmadilloBackupMessage.BackupMessage.Metadata.FrankingMetadataRfrankingMetadata&
|
||||
payloadVersion (RpayloadVersion0
|
||||
futureProofBehavior (RfutureProofBehaviorX
|
||||
FrankingMetadata
|
||||
frankingTag (RfrankingTag"
|
||||
reportingTag (RreportingTagB?Z=go.mau.fi/whatsmeow/binary/armadillo/waArmadilloBackupMessagebproto3
|
@ -0,0 +1,22 @@
|
||||
syntax = "proto3";
|
||||
package WAArmadilloBackupMessage;
|
||||
option go_package = "go.mau.fi/whatsmeow/binary/armadillo/waArmadilloBackupMessage";
|
||||
|
||||
message BackupMessage {
|
||||
message Metadata {
|
||||
message FrankingMetadata {
|
||||
bytes frankingTag = 3;
|
||||
bytes reportingTag = 4;
|
||||
}
|
||||
|
||||
string senderID = 1;
|
||||
string messageID = 2;
|
||||
int64 timestampMS = 3;
|
||||
FrankingMetadata frankingMetadata = 4;
|
||||
int32 payloadVersion = 5;
|
||||
int32 futureProofBehavior = 6;
|
||||
}
|
||||
|
||||
Metadata metadata = 1;
|
||||
bytes payload = 2;
|
||||
}
|
231
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloICDC/WAArmadilloICDC.pb.go
vendored
Normal file
231
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloICDC/WAArmadilloICDC.pb.go
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v3.21.12
|
||||
// source: waArmadilloICDC/WAArmadilloICDC.proto
|
||||
|
||||
package waArmadilloICDC
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ICDCIdentityList struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Seq int32 `protobuf:"varint,1,opt,name=seq,proto3" json:"seq,omitempty"`
|
||||
Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
Devices [][]byte `protobuf:"bytes,3,rep,name=devices,proto3" json:"devices,omitempty"`
|
||||
SigningDeviceIndex int32 `protobuf:"varint,4,opt,name=signingDeviceIndex,proto3" json:"signingDeviceIndex,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ICDCIdentityList) Reset() {
|
||||
*x = ICDCIdentityList{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ICDCIdentityList) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ICDCIdentityList) ProtoMessage() {}
|
||||
|
||||
func (x *ICDCIdentityList) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ICDCIdentityList.ProtoReflect.Descriptor instead.
|
||||
func (*ICDCIdentityList) Descriptor() ([]byte, []int) {
|
||||
return file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ICDCIdentityList) GetSeq() int32 {
|
||||
if x != nil {
|
||||
return x.Seq
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ICDCIdentityList) GetTimestamp() int64 {
|
||||
if x != nil {
|
||||
return x.Timestamp
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ICDCIdentityList) GetDevices() [][]byte {
|
||||
if x != nil {
|
||||
return x.Devices
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ICDCIdentityList) GetSigningDeviceIndex() int32 {
|
||||
if x != nil {
|
||||
return x.SigningDeviceIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type SignedICDCIdentityList struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Details []byte `protobuf:"bytes,1,opt,name=details,proto3" json:"details,omitempty"`
|
||||
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SignedICDCIdentityList) Reset() {
|
||||
*x = SignedICDCIdentityList{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SignedICDCIdentityList) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SignedICDCIdentityList) ProtoMessage() {}
|
||||
|
||||
func (x *SignedICDCIdentityList) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SignedICDCIdentityList.ProtoReflect.Descriptor instead.
|
||||
func (*SignedICDCIdentityList) Descriptor() ([]byte, []int) {
|
||||
return file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *SignedICDCIdentityList) GetDetails() []byte {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SignedICDCIdentityList) GetSignature() []byte {
|
||||
if x != nil {
|
||||
return x.Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_waArmadilloICDC_WAArmadilloICDC_proto protoreflect.FileDescriptor
|
||||
|
||||
//go:embed WAArmadilloICDC.pb.raw
|
||||
var file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc []byte
|
||||
|
||||
var (
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescOnce sync.Once
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescData = file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescGZIP() []byte {
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescOnce.Do(func() {
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescData = protoimpl.X.CompressGZIP(file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescData)
|
||||
})
|
||||
return file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_waArmadilloICDC_WAArmadilloICDC_proto_goTypes = []interface{}{
|
||||
(*ICDCIdentityList)(nil), // 0: WAArmadilloICDC.ICDCIdentityList
|
||||
(*SignedICDCIdentityList)(nil), // 1: WAArmadilloICDC.SignedICDCIdentityList
|
||||
}
|
||||
var file_waArmadilloICDC_WAArmadilloICDC_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_waArmadilloICDC_WAArmadilloICDC_proto_init() }
|
||||
func file_waArmadilloICDC_WAArmadilloICDC_proto_init() {
|
||||
if File_waArmadilloICDC_WAArmadilloICDC_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ICDCIdentityList); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SignedICDCIdentityList); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_waArmadilloICDC_WAArmadilloICDC_proto_goTypes,
|
||||
DependencyIndexes: file_waArmadilloICDC_WAArmadilloICDC_proto_depIdxs,
|
||||
MessageInfos: file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes,
|
||||
}.Build()
|
||||
File_waArmadilloICDC_WAArmadilloICDC_proto = out.File
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc = nil
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_goTypes = nil
|
||||
file_waArmadilloICDC_WAArmadilloICDC_proto_depIdxs = nil
|
||||
}
|
10
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloICDC/WAArmadilloICDC.pb.raw
vendored
Normal file
10
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloICDC/WAArmadilloICDC.pb.raw
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
%waArmadilloICDC/WAArmadilloICDC.protoWAArmadilloICDC"Œ
|
||||
ICDCIdentityList
|
||||
seq (Rseq
|
||||
timestamp (R timestamp
|
||||
devices (Rdevices.
|
||||
signingDeviceIndex (RsigningDeviceIndex"P
|
||||
SignedICDCIdentityList
|
||||
details (Rdetails
|
||||
signature (R signatureB6Z4go.mau.fi/whatsmeow/binary/armadillo/waArmadilloICDCbproto3
|
15
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloICDC/WAArmadilloICDC.proto
vendored
Normal file
15
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloICDC/WAArmadilloICDC.proto
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
syntax = "proto3";
|
||||
package WAArmadilloICDC;
|
||||
option go_package = "go.mau.fi/whatsmeow/binary/armadillo/waArmadilloICDC";
|
||||
|
||||
message ICDCIdentityList {
|
||||
int32 seq = 1;
|
||||
int64 timestamp = 2;
|
||||
repeated bytes devices = 3;
|
||||
int32 signingDeviceIndex = 4;
|
||||
}
|
||||
|
||||
message SignedICDCIdentityList {
|
||||
bytes details = 1;
|
||||
bytes signature = 2;
|
||||
}
|
785
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloXMA/WAArmadilloXMA.pb.go
vendored
Normal file
785
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloXMA/WAArmadilloXMA.pb.go
vendored
Normal file
@ -0,0 +1,785 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v3.21.12
|
||||
// source: waArmadilloXMA/WAArmadilloXMA.proto
|
||||
|
||||
package waArmadilloXMA
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
waCommon "go.mau.fi/whatsmeow/binary/armadillo/waCommon"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ExtendedContentMessage_OverlayIconGlyph int32
|
||||
|
||||
const (
|
||||
ExtendedContentMessage_INFO ExtendedContentMessage_OverlayIconGlyph = 0
|
||||
ExtendedContentMessage_EYE_OFF ExtendedContentMessage_OverlayIconGlyph = 1
|
||||
ExtendedContentMessage_NEWS_OFF ExtendedContentMessage_OverlayIconGlyph = 2
|
||||
ExtendedContentMessage_WARNING ExtendedContentMessage_OverlayIconGlyph = 3
|
||||
ExtendedContentMessage_PRIVATE ExtendedContentMessage_OverlayIconGlyph = 4
|
||||
ExtendedContentMessage_NONE ExtendedContentMessage_OverlayIconGlyph = 5
|
||||
ExtendedContentMessage_MEDIA_LABEL ExtendedContentMessage_OverlayIconGlyph = 6
|
||||
ExtendedContentMessage_POST_COVER ExtendedContentMessage_OverlayIconGlyph = 7
|
||||
ExtendedContentMessage_POST_LABEL ExtendedContentMessage_OverlayIconGlyph = 8
|
||||
ExtendedContentMessage_WARNING_SCREENS ExtendedContentMessage_OverlayIconGlyph = 9
|
||||
)
|
||||
|
||||
// Enum value maps for ExtendedContentMessage_OverlayIconGlyph.
|
||||
var (
|
||||
ExtendedContentMessage_OverlayIconGlyph_name = map[int32]string{
|
||||
0: "INFO",
|
||||
1: "EYE_OFF",
|
||||
2: "NEWS_OFF",
|
||||
3: "WARNING",
|
||||
4: "PRIVATE",
|
||||
5: "NONE",
|
||||
6: "MEDIA_LABEL",
|
||||
7: "POST_COVER",
|
||||
8: "POST_LABEL",
|
||||
9: "WARNING_SCREENS",
|
||||
}
|
||||
ExtendedContentMessage_OverlayIconGlyph_value = map[string]int32{
|
||||
"INFO": 0,
|
||||
"EYE_OFF": 1,
|
||||
"NEWS_OFF": 2,
|
||||
"WARNING": 3,
|
||||
"PRIVATE": 4,
|
||||
"NONE": 5,
|
||||
"MEDIA_LABEL": 6,
|
||||
"POST_COVER": 7,
|
||||
"POST_LABEL": 8,
|
||||
"WARNING_SCREENS": 9,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ExtendedContentMessage_OverlayIconGlyph) Enum() *ExtendedContentMessage_OverlayIconGlyph {
|
||||
p := new(ExtendedContentMessage_OverlayIconGlyph)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ExtendedContentMessage_OverlayIconGlyph) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ExtendedContentMessage_OverlayIconGlyph) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (ExtendedContentMessage_OverlayIconGlyph) Type() protoreflect.EnumType {
|
||||
return &file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x ExtendedContentMessage_OverlayIconGlyph) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExtendedContentMessage_OverlayIconGlyph.Descriptor instead.
|
||||
func (ExtendedContentMessage_OverlayIconGlyph) EnumDescriptor() ([]byte, []int) {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
type ExtendedContentMessage_CtaButtonType int32
|
||||
|
||||
const (
|
||||
ExtendedContentMessage_CTABUTTONTYPE_UNKNOWN ExtendedContentMessage_CtaButtonType = 0
|
||||
ExtendedContentMessage_OPEN_NATIVE ExtendedContentMessage_CtaButtonType = 11
|
||||
)
|
||||
|
||||
// Enum value maps for ExtendedContentMessage_CtaButtonType.
|
||||
var (
|
||||
ExtendedContentMessage_CtaButtonType_name = map[int32]string{
|
||||
0: "CTABUTTONTYPE_UNKNOWN",
|
||||
11: "OPEN_NATIVE",
|
||||
}
|
||||
ExtendedContentMessage_CtaButtonType_value = map[string]int32{
|
||||
"CTABUTTONTYPE_UNKNOWN": 0,
|
||||
"OPEN_NATIVE": 11,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ExtendedContentMessage_CtaButtonType) Enum() *ExtendedContentMessage_CtaButtonType {
|
||||
p := new(ExtendedContentMessage_CtaButtonType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ExtendedContentMessage_CtaButtonType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ExtendedContentMessage_CtaButtonType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (ExtendedContentMessage_CtaButtonType) Type() protoreflect.EnumType {
|
||||
return &file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x ExtendedContentMessage_CtaButtonType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExtendedContentMessage_CtaButtonType.Descriptor instead.
|
||||
func (ExtendedContentMessage_CtaButtonType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescGZIP(), []int{0, 1}
|
||||
}
|
||||
|
||||
type ExtendedContentMessage_XmaLayoutType int32
|
||||
|
||||
const (
|
||||
ExtendedContentMessage_SINGLE ExtendedContentMessage_XmaLayoutType = 0
|
||||
ExtendedContentMessage_PORTRAIT ExtendedContentMessage_XmaLayoutType = 3
|
||||
ExtendedContentMessage_STANDARD_DXMA ExtendedContentMessage_XmaLayoutType = 12
|
||||
ExtendedContentMessage_LIST_DXMA ExtendedContentMessage_XmaLayoutType = 15
|
||||
)
|
||||
|
||||
// Enum value maps for ExtendedContentMessage_XmaLayoutType.
|
||||
var (
|
||||
ExtendedContentMessage_XmaLayoutType_name = map[int32]string{
|
||||
0: "SINGLE",
|
||||
3: "PORTRAIT",
|
||||
12: "STANDARD_DXMA",
|
||||
15: "LIST_DXMA",
|
||||
}
|
||||
ExtendedContentMessage_XmaLayoutType_value = map[string]int32{
|
||||
"SINGLE": 0,
|
||||
"PORTRAIT": 3,
|
||||
"STANDARD_DXMA": 12,
|
||||
"LIST_DXMA": 15,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ExtendedContentMessage_XmaLayoutType) Enum() *ExtendedContentMessage_XmaLayoutType {
|
||||
p := new(ExtendedContentMessage_XmaLayoutType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ExtendedContentMessage_XmaLayoutType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ExtendedContentMessage_XmaLayoutType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes[2].Descriptor()
|
||||
}
|
||||
|
||||
func (ExtendedContentMessage_XmaLayoutType) Type() protoreflect.EnumType {
|
||||
return &file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes[2]
|
||||
}
|
||||
|
||||
func (x ExtendedContentMessage_XmaLayoutType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExtendedContentMessage_XmaLayoutType.Descriptor instead.
|
||||
func (ExtendedContentMessage_XmaLayoutType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescGZIP(), []int{0, 2}
|
||||
}
|
||||
|
||||
type ExtendedContentMessage_ExtendedContentType int32
|
||||
|
||||
const (
|
||||
ExtendedContentMessage_EXTENDEDCONTENTTYPE_UNKNOWN ExtendedContentMessage_ExtendedContentType = 0
|
||||
ExtendedContentMessage_IG_STORY_PHOTO_MENTION ExtendedContentMessage_ExtendedContentType = 4
|
||||
ExtendedContentMessage_IG_SINGLE_IMAGE_POST_SHARE ExtendedContentMessage_ExtendedContentType = 9
|
||||
ExtendedContentMessage_IG_MULTIPOST_SHARE ExtendedContentMessage_ExtendedContentType = 10
|
||||
ExtendedContentMessage_IG_SINGLE_VIDEO_POST_SHARE ExtendedContentMessage_ExtendedContentType = 11
|
||||
ExtendedContentMessage_IG_STORY_PHOTO_SHARE ExtendedContentMessage_ExtendedContentType = 12
|
||||
ExtendedContentMessage_IG_STORY_VIDEO_SHARE ExtendedContentMessage_ExtendedContentType = 13
|
||||
ExtendedContentMessage_IG_CLIPS_SHARE ExtendedContentMessage_ExtendedContentType = 14
|
||||
ExtendedContentMessage_IG_IGTV_SHARE ExtendedContentMessage_ExtendedContentType = 15
|
||||
ExtendedContentMessage_IG_SHOP_SHARE ExtendedContentMessage_ExtendedContentType = 16
|
||||
ExtendedContentMessage_IG_PROFILE_SHARE ExtendedContentMessage_ExtendedContentType = 19
|
||||
ExtendedContentMessage_IG_STORY_PHOTO_HIGHLIGHT_SHARE ExtendedContentMessage_ExtendedContentType = 20
|
||||
ExtendedContentMessage_IG_STORY_VIDEO_HIGHLIGHT_SHARE ExtendedContentMessage_ExtendedContentType = 21
|
||||
ExtendedContentMessage_IG_STORY_REPLY ExtendedContentMessage_ExtendedContentType = 22
|
||||
ExtendedContentMessage_IG_STORY_REACTION ExtendedContentMessage_ExtendedContentType = 23
|
||||
ExtendedContentMessage_IG_STORY_VIDEO_MENTION ExtendedContentMessage_ExtendedContentType = 24
|
||||
ExtendedContentMessage_IG_STORY_HIGHLIGHT_REPLY ExtendedContentMessage_ExtendedContentType = 25
|
||||
ExtendedContentMessage_IG_STORY_HIGHLIGHT_REACTION ExtendedContentMessage_ExtendedContentType = 26
|
||||
ExtendedContentMessage_IG_EXTERNAL_LINK ExtendedContentMessage_ExtendedContentType = 27
|
||||
ExtendedContentMessage_IG_RECEIVER_FETCH ExtendedContentMessage_ExtendedContentType = 28
|
||||
ExtendedContentMessage_FB_FEED_SHARE ExtendedContentMessage_ExtendedContentType = 1000
|
||||
ExtendedContentMessage_FB_STORY_REPLY ExtendedContentMessage_ExtendedContentType = 1001
|
||||
ExtendedContentMessage_FB_STORY_SHARE ExtendedContentMessage_ExtendedContentType = 1002
|
||||
ExtendedContentMessage_FB_STORY_MENTION ExtendedContentMessage_ExtendedContentType = 1003
|
||||
ExtendedContentMessage_FB_FEED_VIDEO_SHARE ExtendedContentMessage_ExtendedContentType = 1004
|
||||
ExtendedContentMessage_FB_GAMING_CUSTOM_UPDATE ExtendedContentMessage_ExtendedContentType = 1005
|
||||
ExtendedContentMessage_FB_PRODUCER_STORY_REPLY ExtendedContentMessage_ExtendedContentType = 1006
|
||||
ExtendedContentMessage_FB_EVENT ExtendedContentMessage_ExtendedContentType = 1007
|
||||
ExtendedContentMessage_FB_FEED_POST_PRIVATE_REPLY ExtendedContentMessage_ExtendedContentType = 1008
|
||||
ExtendedContentMessage_FB_SHORT ExtendedContentMessage_ExtendedContentType = 1009
|
||||
ExtendedContentMessage_FB_COMMENT_MENTION_SHARE ExtendedContentMessage_ExtendedContentType = 1010
|
||||
ExtendedContentMessage_MSG_EXTERNAL_LINK_SHARE ExtendedContentMessage_ExtendedContentType = 2000
|
||||
ExtendedContentMessage_MSG_P2P_PAYMENT ExtendedContentMessage_ExtendedContentType = 2001
|
||||
ExtendedContentMessage_MSG_LOCATION_SHARING ExtendedContentMessage_ExtendedContentType = 2002
|
||||
ExtendedContentMessage_MSG_LOCATION_SHARING_V2 ExtendedContentMessage_ExtendedContentType = 2003
|
||||
ExtendedContentMessage_MSG_HIGHLIGHTS_TAB_FRIEND_UPDATES_REPLY ExtendedContentMessage_ExtendedContentType = 2004
|
||||
ExtendedContentMessage_MSG_HIGHLIGHTS_TAB_LOCAL_EVENT_REPLY ExtendedContentMessage_ExtendedContentType = 2005
|
||||
ExtendedContentMessage_MSG_RECEIVER_FETCH ExtendedContentMessage_ExtendedContentType = 2006
|
||||
ExtendedContentMessage_MSG_IG_MEDIA_SHARE ExtendedContentMessage_ExtendedContentType = 2007
|
||||
ExtendedContentMessage_MSG_GEN_AI_SEARCH_PLUGIN_RESPONSE ExtendedContentMessage_ExtendedContentType = 2008
|
||||
ExtendedContentMessage_MSG_REELS_LIST ExtendedContentMessage_ExtendedContentType = 2009
|
||||
ExtendedContentMessage_MSG_CONTACT ExtendedContentMessage_ExtendedContentType = 2010
|
||||
ExtendedContentMessage_RTC_AUDIO_CALL ExtendedContentMessage_ExtendedContentType = 3000
|
||||
ExtendedContentMessage_RTC_VIDEO_CALL ExtendedContentMessage_ExtendedContentType = 3001
|
||||
ExtendedContentMessage_RTC_MISSED_AUDIO_CALL ExtendedContentMessage_ExtendedContentType = 3002
|
||||
ExtendedContentMessage_RTC_MISSED_VIDEO_CALL ExtendedContentMessage_ExtendedContentType = 3003
|
||||
ExtendedContentMessage_RTC_GROUP_AUDIO_CALL ExtendedContentMessage_ExtendedContentType = 3004
|
||||
ExtendedContentMessage_RTC_GROUP_VIDEO_CALL ExtendedContentMessage_ExtendedContentType = 3005
|
||||
ExtendedContentMessage_RTC_MISSED_GROUP_AUDIO_CALL ExtendedContentMessage_ExtendedContentType = 3006
|
||||
ExtendedContentMessage_RTC_MISSED_GROUP_VIDEO_CALL ExtendedContentMessage_ExtendedContentType = 3007
|
||||
ExtendedContentMessage_DATACLASS_SENDER_COPY ExtendedContentMessage_ExtendedContentType = 4000
|
||||
)
|
||||
|
||||
// Enum value maps for ExtendedContentMessage_ExtendedContentType.
|
||||
var (
|
||||
ExtendedContentMessage_ExtendedContentType_name = map[int32]string{
|
||||
0: "EXTENDEDCONTENTTYPE_UNKNOWN",
|
||||
4: "IG_STORY_PHOTO_MENTION",
|
||||
9: "IG_SINGLE_IMAGE_POST_SHARE",
|
||||
10: "IG_MULTIPOST_SHARE",
|
||||
11: "IG_SINGLE_VIDEO_POST_SHARE",
|
||||
12: "IG_STORY_PHOTO_SHARE",
|
||||
13: "IG_STORY_VIDEO_SHARE",
|
||||
14: "IG_CLIPS_SHARE",
|
||||
15: "IG_IGTV_SHARE",
|
||||
16: "IG_SHOP_SHARE",
|
||||
19: "IG_PROFILE_SHARE",
|
||||
20: "IG_STORY_PHOTO_HIGHLIGHT_SHARE",
|
||||
21: "IG_STORY_VIDEO_HIGHLIGHT_SHARE",
|
||||
22: "IG_STORY_REPLY",
|
||||
23: "IG_STORY_REACTION",
|
||||
24: "IG_STORY_VIDEO_MENTION",
|
||||
25: "IG_STORY_HIGHLIGHT_REPLY",
|
||||
26: "IG_STORY_HIGHLIGHT_REACTION",
|
||||
27: "IG_EXTERNAL_LINK",
|
||||
28: "IG_RECEIVER_FETCH",
|
||||
1000: "FB_FEED_SHARE",
|
||||
1001: "FB_STORY_REPLY",
|
||||
1002: "FB_STORY_SHARE",
|
||||
1003: "FB_STORY_MENTION",
|
||||
1004: "FB_FEED_VIDEO_SHARE",
|
||||
1005: "FB_GAMING_CUSTOM_UPDATE",
|
||||
1006: "FB_PRODUCER_STORY_REPLY",
|
||||
1007: "FB_EVENT",
|
||||
1008: "FB_FEED_POST_PRIVATE_REPLY",
|
||||
1009: "FB_SHORT",
|
||||
1010: "FB_COMMENT_MENTION_SHARE",
|
||||
2000: "MSG_EXTERNAL_LINK_SHARE",
|
||||
2001: "MSG_P2P_PAYMENT",
|
||||
2002: "MSG_LOCATION_SHARING",
|
||||
2003: "MSG_LOCATION_SHARING_V2",
|
||||
2004: "MSG_HIGHLIGHTS_TAB_FRIEND_UPDATES_REPLY",
|
||||
2005: "MSG_HIGHLIGHTS_TAB_LOCAL_EVENT_REPLY",
|
||||
2006: "MSG_RECEIVER_FETCH",
|
||||
2007: "MSG_IG_MEDIA_SHARE",
|
||||
2008: "MSG_GEN_AI_SEARCH_PLUGIN_RESPONSE",
|
||||
2009: "MSG_REELS_LIST",
|
||||
2010: "MSG_CONTACT",
|
||||
3000: "RTC_AUDIO_CALL",
|
||||
3001: "RTC_VIDEO_CALL",
|
||||
3002: "RTC_MISSED_AUDIO_CALL",
|
||||
3003: "RTC_MISSED_VIDEO_CALL",
|
||||
3004: "RTC_GROUP_AUDIO_CALL",
|
||||
3005: "RTC_GROUP_VIDEO_CALL",
|
||||
3006: "RTC_MISSED_GROUP_AUDIO_CALL",
|
||||
3007: "RTC_MISSED_GROUP_VIDEO_CALL",
|
||||
4000: "DATACLASS_SENDER_COPY",
|
||||
}
|
||||
ExtendedContentMessage_ExtendedContentType_value = map[string]int32{
|
||||
"EXTENDEDCONTENTTYPE_UNKNOWN": 0,
|
||||
"IG_STORY_PHOTO_MENTION": 4,
|
||||
"IG_SINGLE_IMAGE_POST_SHARE": 9,
|
||||
"IG_MULTIPOST_SHARE": 10,
|
||||
"IG_SINGLE_VIDEO_POST_SHARE": 11,
|
||||
"IG_STORY_PHOTO_SHARE": 12,
|
||||
"IG_STORY_VIDEO_SHARE": 13,
|
||||
"IG_CLIPS_SHARE": 14,
|
||||
"IG_IGTV_SHARE": 15,
|
||||
"IG_SHOP_SHARE": 16,
|
||||
"IG_PROFILE_SHARE": 19,
|
||||
"IG_STORY_PHOTO_HIGHLIGHT_SHARE": 20,
|
||||
"IG_STORY_VIDEO_HIGHLIGHT_SHARE": 21,
|
||||
"IG_STORY_REPLY": 22,
|
||||
"IG_STORY_REACTION": 23,
|
||||
"IG_STORY_VIDEO_MENTION": 24,
|
||||
"IG_STORY_HIGHLIGHT_REPLY": 25,
|
||||
"IG_STORY_HIGHLIGHT_REACTION": 26,
|
||||
"IG_EXTERNAL_LINK": 27,
|
||||
"IG_RECEIVER_FETCH": 28,
|
||||
"FB_FEED_SHARE": 1000,
|
||||
"FB_STORY_REPLY": 1001,
|
||||
"FB_STORY_SHARE": 1002,
|
||||
"FB_STORY_MENTION": 1003,
|
||||
"FB_FEED_VIDEO_SHARE": 1004,
|
||||
"FB_GAMING_CUSTOM_UPDATE": 1005,
|
||||
"FB_PRODUCER_STORY_REPLY": 1006,
|
||||
"FB_EVENT": 1007,
|
||||
"FB_FEED_POST_PRIVATE_REPLY": 1008,
|
||||
"FB_SHORT": 1009,
|
||||
"FB_COMMENT_MENTION_SHARE": 1010,
|
||||
"MSG_EXTERNAL_LINK_SHARE": 2000,
|
||||
"MSG_P2P_PAYMENT": 2001,
|
||||
"MSG_LOCATION_SHARING": 2002,
|
||||
"MSG_LOCATION_SHARING_V2": 2003,
|
||||
"MSG_HIGHLIGHTS_TAB_FRIEND_UPDATES_REPLY": 2004,
|
||||
"MSG_HIGHLIGHTS_TAB_LOCAL_EVENT_REPLY": 2005,
|
||||
"MSG_RECEIVER_FETCH": 2006,
|
||||
"MSG_IG_MEDIA_SHARE": 2007,
|
||||
"MSG_GEN_AI_SEARCH_PLUGIN_RESPONSE": 2008,
|
||||
"MSG_REELS_LIST": 2009,
|
||||
"MSG_CONTACT": 2010,
|
||||
"RTC_AUDIO_CALL": 3000,
|
||||
"RTC_VIDEO_CALL": 3001,
|
||||
"RTC_MISSED_AUDIO_CALL": 3002,
|
||||
"RTC_MISSED_VIDEO_CALL": 3003,
|
||||
"RTC_GROUP_AUDIO_CALL": 3004,
|
||||
"RTC_GROUP_VIDEO_CALL": 3005,
|
||||
"RTC_MISSED_GROUP_AUDIO_CALL": 3006,
|
||||
"RTC_MISSED_GROUP_VIDEO_CALL": 3007,
|
||||
"DATACLASS_SENDER_COPY": 4000,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ExtendedContentMessage_ExtendedContentType) Enum() *ExtendedContentMessage_ExtendedContentType {
|
||||
p := new(ExtendedContentMessage_ExtendedContentType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ExtendedContentMessage_ExtendedContentType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ExtendedContentMessage_ExtendedContentType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes[3].Descriptor()
|
||||
}
|
||||
|
||||
func (ExtendedContentMessage_ExtendedContentType) Type() protoreflect.EnumType {
|
||||
return &file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes[3]
|
||||
}
|
||||
|
||||
func (x ExtendedContentMessage_ExtendedContentType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExtendedContentMessage_ExtendedContentType.Descriptor instead.
|
||||
func (ExtendedContentMessage_ExtendedContentType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescGZIP(), []int{0, 3}
|
||||
}
|
||||
|
||||
type ExtendedContentMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AssociatedMessage *waCommon.SubProtocol `protobuf:"bytes,1,opt,name=associatedMessage,proto3" json:"associatedMessage,omitempty"`
|
||||
TargetType ExtendedContentMessage_ExtendedContentType `protobuf:"varint,2,opt,name=targetType,proto3,enum=WAArmadilloXMA.ExtendedContentMessage_ExtendedContentType" json:"targetType,omitempty"`
|
||||
TargetUsername string `protobuf:"bytes,3,opt,name=targetUsername,proto3" json:"targetUsername,omitempty"`
|
||||
TargetID string `protobuf:"bytes,4,opt,name=targetID,proto3" json:"targetID,omitempty"`
|
||||
TargetExpiringAtSec int64 `protobuf:"varint,5,opt,name=targetExpiringAtSec,proto3" json:"targetExpiringAtSec,omitempty"`
|
||||
XmaLayoutType ExtendedContentMessage_XmaLayoutType `protobuf:"varint,6,opt,name=xmaLayoutType,proto3,enum=WAArmadilloXMA.ExtendedContentMessage_XmaLayoutType" json:"xmaLayoutType,omitempty"`
|
||||
Ctas []*ExtendedContentMessage_CTA `protobuf:"bytes,7,rep,name=ctas,proto3" json:"ctas,omitempty"`
|
||||
Previews []*waCommon.SubProtocol `protobuf:"bytes,8,rep,name=previews,proto3" json:"previews,omitempty"`
|
||||
TitleText string `protobuf:"bytes,9,opt,name=titleText,proto3" json:"titleText,omitempty"`
|
||||
SubtitleText string `protobuf:"bytes,10,opt,name=subtitleText,proto3" json:"subtitleText,omitempty"`
|
||||
MaxTitleNumOfLines uint32 `protobuf:"varint,11,opt,name=maxTitleNumOfLines,proto3" json:"maxTitleNumOfLines,omitempty"`
|
||||
MaxSubtitleNumOfLines uint32 `protobuf:"varint,12,opt,name=maxSubtitleNumOfLines,proto3" json:"maxSubtitleNumOfLines,omitempty"`
|
||||
Favicon *waCommon.SubProtocol `protobuf:"bytes,13,opt,name=favicon,proto3" json:"favicon,omitempty"`
|
||||
HeaderImage *waCommon.SubProtocol `protobuf:"bytes,14,opt,name=headerImage,proto3" json:"headerImage,omitempty"`
|
||||
HeaderTitle string `protobuf:"bytes,15,opt,name=headerTitle,proto3" json:"headerTitle,omitempty"`
|
||||
OverlayIconGlyph ExtendedContentMessage_OverlayIconGlyph `protobuf:"varint,16,opt,name=overlayIconGlyph,proto3,enum=WAArmadilloXMA.ExtendedContentMessage_OverlayIconGlyph" json:"overlayIconGlyph,omitempty"`
|
||||
OverlayTitle string `protobuf:"bytes,17,opt,name=overlayTitle,proto3" json:"overlayTitle,omitempty"`
|
||||
OverlayDescription string `protobuf:"bytes,18,opt,name=overlayDescription,proto3" json:"overlayDescription,omitempty"`
|
||||
SentWithMessageID string `protobuf:"bytes,19,opt,name=sentWithMessageID,proto3" json:"sentWithMessageID,omitempty"`
|
||||
MessageText string `protobuf:"bytes,20,opt,name=messageText,proto3" json:"messageText,omitempty"`
|
||||
HeaderSubtitle string `protobuf:"bytes,21,opt,name=headerSubtitle,proto3" json:"headerSubtitle,omitempty"`
|
||||
XmaDataclass string `protobuf:"bytes,22,opt,name=xmaDataclass,proto3" json:"xmaDataclass,omitempty"`
|
||||
ContentRef string `protobuf:"bytes,23,opt,name=contentRef,proto3" json:"contentRef,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) Reset() {
|
||||
*x = ExtendedContentMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waArmadilloXMA_WAArmadilloXMA_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ExtendedContentMessage) ProtoMessage() {}
|
||||
|
||||
func (x *ExtendedContentMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waArmadilloXMA_WAArmadilloXMA_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExtendedContentMessage.ProtoReflect.Descriptor instead.
|
||||
func (*ExtendedContentMessage) Descriptor() ([]byte, []int) {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetAssociatedMessage() *waCommon.SubProtocol {
|
||||
if x != nil {
|
||||
return x.AssociatedMessage
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetTargetType() ExtendedContentMessage_ExtendedContentType {
|
||||
if x != nil {
|
||||
return x.TargetType
|
||||
}
|
||||
return ExtendedContentMessage_EXTENDEDCONTENTTYPE_UNKNOWN
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetTargetUsername() string {
|
||||
if x != nil {
|
||||
return x.TargetUsername
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetTargetID() string {
|
||||
if x != nil {
|
||||
return x.TargetID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetTargetExpiringAtSec() int64 {
|
||||
if x != nil {
|
||||
return x.TargetExpiringAtSec
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetXmaLayoutType() ExtendedContentMessage_XmaLayoutType {
|
||||
if x != nil {
|
||||
return x.XmaLayoutType
|
||||
}
|
||||
return ExtendedContentMessage_SINGLE
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetCtas() []*ExtendedContentMessage_CTA {
|
||||
if x != nil {
|
||||
return x.Ctas
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetPreviews() []*waCommon.SubProtocol {
|
||||
if x != nil {
|
||||
return x.Previews
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetTitleText() string {
|
||||
if x != nil {
|
||||
return x.TitleText
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetSubtitleText() string {
|
||||
if x != nil {
|
||||
return x.SubtitleText
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetMaxTitleNumOfLines() uint32 {
|
||||
if x != nil {
|
||||
return x.MaxTitleNumOfLines
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetMaxSubtitleNumOfLines() uint32 {
|
||||
if x != nil {
|
||||
return x.MaxSubtitleNumOfLines
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetFavicon() *waCommon.SubProtocol {
|
||||
if x != nil {
|
||||
return x.Favicon
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetHeaderImage() *waCommon.SubProtocol {
|
||||
if x != nil {
|
||||
return x.HeaderImage
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetHeaderTitle() string {
|
||||
if x != nil {
|
||||
return x.HeaderTitle
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetOverlayIconGlyph() ExtendedContentMessage_OverlayIconGlyph {
|
||||
if x != nil {
|
||||
return x.OverlayIconGlyph
|
||||
}
|
||||
return ExtendedContentMessage_INFO
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetOverlayTitle() string {
|
||||
if x != nil {
|
||||
return x.OverlayTitle
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetOverlayDescription() string {
|
||||
if x != nil {
|
||||
return x.OverlayDescription
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetSentWithMessageID() string {
|
||||
if x != nil {
|
||||
return x.SentWithMessageID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetMessageText() string {
|
||||
if x != nil {
|
||||
return x.MessageText
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetHeaderSubtitle() string {
|
||||
if x != nil {
|
||||
return x.HeaderSubtitle
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetXmaDataclass() string {
|
||||
if x != nil {
|
||||
return x.XmaDataclass
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage) GetContentRef() string {
|
||||
if x != nil {
|
||||
return x.ContentRef
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ExtendedContentMessage_CTA struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ButtonType ExtendedContentMessage_CtaButtonType `protobuf:"varint,1,opt,name=buttonType,proto3,enum=WAArmadilloXMA.ExtendedContentMessage_CtaButtonType" json:"buttonType,omitempty"`
|
||||
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
|
||||
ActionURL string `protobuf:"bytes,3,opt,name=actionURL,proto3" json:"actionURL,omitempty"`
|
||||
NativeURL string `protobuf:"bytes,4,opt,name=nativeURL,proto3" json:"nativeURL,omitempty"`
|
||||
CtaType string `protobuf:"bytes,5,opt,name=ctaType,proto3" json:"ctaType,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage_CTA) Reset() {
|
||||
*x = ExtendedContentMessage_CTA{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waArmadilloXMA_WAArmadilloXMA_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage_CTA) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ExtendedContentMessage_CTA) ProtoMessage() {}
|
||||
|
||||
func (x *ExtendedContentMessage_CTA) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waArmadilloXMA_WAArmadilloXMA_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExtendedContentMessage_CTA.ProtoReflect.Descriptor instead.
|
||||
func (*ExtendedContentMessage_CTA) Descriptor() ([]byte, []int) {
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage_CTA) GetButtonType() ExtendedContentMessage_CtaButtonType {
|
||||
if x != nil {
|
||||
return x.ButtonType
|
||||
}
|
||||
return ExtendedContentMessage_CTABUTTONTYPE_UNKNOWN
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage_CTA) GetTitle() string {
|
||||
if x != nil {
|
||||
return x.Title
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage_CTA) GetActionURL() string {
|
||||
if x != nil {
|
||||
return x.ActionURL
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage_CTA) GetNativeURL() string {
|
||||
if x != nil {
|
||||
return x.NativeURL
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExtendedContentMessage_CTA) GetCtaType() string {
|
||||
if x != nil {
|
||||
return x.CtaType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_waArmadilloXMA_WAArmadilloXMA_proto protoreflect.FileDescriptor
|
||||
|
||||
//go:embed WAArmadilloXMA.pb.raw
|
||||
var file_waArmadilloXMA_WAArmadilloXMA_proto_rawDesc []byte
|
||||
|
||||
var (
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescOnce sync.Once
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescData = file_waArmadilloXMA_WAArmadilloXMA_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescGZIP() []byte {
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescOnce.Do(func() {
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescData = protoimpl.X.CompressGZIP(file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescData)
|
||||
})
|
||||
return file_waArmadilloXMA_WAArmadilloXMA_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
|
||||
var file_waArmadilloXMA_WAArmadilloXMA_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_waArmadilloXMA_WAArmadilloXMA_proto_goTypes = []interface{}{
|
||||
(ExtendedContentMessage_OverlayIconGlyph)(0), // 0: WAArmadilloXMA.ExtendedContentMessage.OverlayIconGlyph
|
||||
(ExtendedContentMessage_CtaButtonType)(0), // 1: WAArmadilloXMA.ExtendedContentMessage.CtaButtonType
|
||||
(ExtendedContentMessage_XmaLayoutType)(0), // 2: WAArmadilloXMA.ExtendedContentMessage.XmaLayoutType
|
||||
(ExtendedContentMessage_ExtendedContentType)(0), // 3: WAArmadilloXMA.ExtendedContentMessage.ExtendedContentType
|
||||
(*ExtendedContentMessage)(nil), // 4: WAArmadilloXMA.ExtendedContentMessage
|
||||
(*ExtendedContentMessage_CTA)(nil), // 5: WAArmadilloXMA.ExtendedContentMessage.CTA
|
||||
(*waCommon.SubProtocol)(nil), // 6: WACommon.SubProtocol
|
||||
}
|
||||
var file_waArmadilloXMA_WAArmadilloXMA_proto_depIdxs = []int32{
|
||||
6, // 0: WAArmadilloXMA.ExtendedContentMessage.associatedMessage:type_name -> WACommon.SubProtocol
|
||||
3, // 1: WAArmadilloXMA.ExtendedContentMessage.targetType:type_name -> WAArmadilloXMA.ExtendedContentMessage.ExtendedContentType
|
||||
2, // 2: WAArmadilloXMA.ExtendedContentMessage.xmaLayoutType:type_name -> WAArmadilloXMA.ExtendedContentMessage.XmaLayoutType
|
||||
5, // 3: WAArmadilloXMA.ExtendedContentMessage.ctas:type_name -> WAArmadilloXMA.ExtendedContentMessage.CTA
|
||||
6, // 4: WAArmadilloXMA.ExtendedContentMessage.previews:type_name -> WACommon.SubProtocol
|
||||
6, // 5: WAArmadilloXMA.ExtendedContentMessage.favicon:type_name -> WACommon.SubProtocol
|
||||
6, // 6: WAArmadilloXMA.ExtendedContentMessage.headerImage:type_name -> WACommon.SubProtocol
|
||||
0, // 7: WAArmadilloXMA.ExtendedContentMessage.overlayIconGlyph:type_name -> WAArmadilloXMA.ExtendedContentMessage.OverlayIconGlyph
|
||||
1, // 8: WAArmadilloXMA.ExtendedContentMessage.CTA.buttonType:type_name -> WAArmadilloXMA.ExtendedContentMessage.CtaButtonType
|
||||
9, // [9:9] is the sub-list for method output_type
|
||||
9, // [9:9] is the sub-list for method input_type
|
||||
9, // [9:9] is the sub-list for extension type_name
|
||||
9, // [9:9] is the sub-list for extension extendee
|
||||
0, // [0:9] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_waArmadilloXMA_WAArmadilloXMA_proto_init() }
|
||||
func file_waArmadilloXMA_WAArmadilloXMA_proto_init() {
|
||||
if File_waArmadilloXMA_WAArmadilloXMA_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ExtendedContentMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ExtendedContentMessage_CTA); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_waArmadilloXMA_WAArmadilloXMA_proto_rawDesc,
|
||||
NumEnums: 4,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_waArmadilloXMA_WAArmadilloXMA_proto_goTypes,
|
||||
DependencyIndexes: file_waArmadilloXMA_WAArmadilloXMA_proto_depIdxs,
|
||||
EnumInfos: file_waArmadilloXMA_WAArmadilloXMA_proto_enumTypes,
|
||||
MessageInfos: file_waArmadilloXMA_WAArmadilloXMA_proto_msgTypes,
|
||||
}.Build()
|
||||
File_waArmadilloXMA_WAArmadilloXMA_proto = out.File
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_rawDesc = nil
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_goTypes = nil
|
||||
file_waArmadilloXMA_WAArmadilloXMA_proto_depIdxs = nil
|
||||
}
|
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloXMA/WAArmadilloXMA.pb.raw
vendored
Normal file
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloXMA/WAArmadilloXMA.pb.raw
vendored
Normal file
Binary file not shown.
118
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloXMA/WAArmadilloXMA.proto
vendored
Normal file
118
vendor/go.mau.fi/whatsmeow/binary/armadillo/waArmadilloXMA/WAArmadilloXMA.proto
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
syntax = "proto3";
|
||||
package WAArmadilloXMA;
|
||||
option go_package = "go.mau.fi/whatsmeow/binary/armadillo/waArmadilloXMA";
|
||||
|
||||
import "waCommon/WACommon.proto";
|
||||
|
||||
message ExtendedContentMessage {
|
||||
enum OverlayIconGlyph {
|
||||
INFO = 0;
|
||||
EYE_OFF = 1;
|
||||
NEWS_OFF = 2;
|
||||
WARNING = 3;
|
||||
PRIVATE = 4;
|
||||
NONE = 5;
|
||||
MEDIA_LABEL = 6;
|
||||
POST_COVER = 7;
|
||||
POST_LABEL = 8;
|
||||
WARNING_SCREENS = 9;
|
||||
}
|
||||
|
||||
enum CtaButtonType {
|
||||
CTABUTTONTYPE_UNKNOWN = 0;
|
||||
OPEN_NATIVE = 11;
|
||||
}
|
||||
|
||||
enum XmaLayoutType {
|
||||
SINGLE = 0;
|
||||
PORTRAIT = 3;
|
||||
STANDARD_DXMA = 12;
|
||||
LIST_DXMA = 15;
|
||||
}
|
||||
|
||||
enum ExtendedContentType {
|
||||
EXTENDEDCONTENTTYPE_UNKNOWN = 0;
|
||||
IG_STORY_PHOTO_MENTION = 4;
|
||||
IG_SINGLE_IMAGE_POST_SHARE = 9;
|
||||
IG_MULTIPOST_SHARE = 10;
|
||||
IG_SINGLE_VIDEO_POST_SHARE = 11;
|
||||
IG_STORY_PHOTO_SHARE = 12;
|
||||
IG_STORY_VIDEO_SHARE = 13;
|
||||
IG_CLIPS_SHARE = 14;
|
||||
IG_IGTV_SHARE = 15;
|
||||
IG_SHOP_SHARE = 16;
|
||||
IG_PROFILE_SHARE = 19;
|
||||
IG_STORY_PHOTO_HIGHLIGHT_SHARE = 20;
|
||||
IG_STORY_VIDEO_HIGHLIGHT_SHARE = 21;
|
||||
IG_STORY_REPLY = 22;
|
||||
IG_STORY_REACTION = 23;
|
||||
IG_STORY_VIDEO_MENTION = 24;
|
||||
IG_STORY_HIGHLIGHT_REPLY = 25;
|
||||
IG_STORY_HIGHLIGHT_REACTION = 26;
|
||||
IG_EXTERNAL_LINK = 27;
|
||||
IG_RECEIVER_FETCH = 28;
|
||||
FB_FEED_SHARE = 1000;
|
||||
FB_STORY_REPLY = 1001;
|
||||
FB_STORY_SHARE = 1002;
|
||||
FB_STORY_MENTION = 1003;
|
||||
FB_FEED_VIDEO_SHARE = 1004;
|
||||
FB_GAMING_CUSTOM_UPDATE = 1005;
|
||||
FB_PRODUCER_STORY_REPLY = 1006;
|
||||
FB_EVENT = 1007;
|
||||
FB_FEED_POST_PRIVATE_REPLY = 1008;
|
||||
FB_SHORT = 1009;
|
||||
FB_COMMENT_MENTION_SHARE = 1010;
|
||||
MSG_EXTERNAL_LINK_SHARE = 2000;
|
||||
MSG_P2P_PAYMENT = 2001;
|
||||
MSG_LOCATION_SHARING = 2002;
|
||||
MSG_LOCATION_SHARING_V2 = 2003;
|
||||
MSG_HIGHLIGHTS_TAB_FRIEND_UPDATES_REPLY = 2004;
|
||||
MSG_HIGHLIGHTS_TAB_LOCAL_EVENT_REPLY = 2005;
|
||||
MSG_RECEIVER_FETCH = 2006;
|
||||
MSG_IG_MEDIA_SHARE = 2007;
|
||||
MSG_GEN_AI_SEARCH_PLUGIN_RESPONSE = 2008;
|
||||
MSG_REELS_LIST = 2009;
|
||||
MSG_CONTACT = 2010;
|
||||
RTC_AUDIO_CALL = 3000;
|
||||
RTC_VIDEO_CALL = 3001;
|
||||
RTC_MISSED_AUDIO_CALL = 3002;
|
||||
RTC_MISSED_VIDEO_CALL = 3003;
|
||||
RTC_GROUP_AUDIO_CALL = 3004;
|
||||
RTC_GROUP_VIDEO_CALL = 3005;
|
||||
RTC_MISSED_GROUP_AUDIO_CALL = 3006;
|
||||
RTC_MISSED_GROUP_VIDEO_CALL = 3007;
|
||||
DATACLASS_SENDER_COPY = 4000;
|
||||
}
|
||||
|
||||
message CTA {
|
||||
CtaButtonType buttonType = 1;
|
||||
string title = 2;
|
||||
string actionURL = 3;
|
||||
string nativeURL = 4;
|
||||
string ctaType = 5;
|
||||
}
|
||||
|
||||
WACommon.SubProtocol associatedMessage = 1;
|
||||
ExtendedContentType targetType = 2;
|
||||
string targetUsername = 3;
|
||||
string targetID = 4;
|
||||
int64 targetExpiringAtSec = 5;
|
||||
XmaLayoutType xmaLayoutType = 6;
|
||||
repeated CTA ctas = 7;
|
||||
repeated WACommon.SubProtocol previews = 8;
|
||||
string titleText = 9;
|
||||
string subtitleText = 10;
|
||||
uint32 maxTitleNumOfLines = 11;
|
||||
uint32 maxSubtitleNumOfLines = 12;
|
||||
WACommon.SubProtocol favicon = 13;
|
||||
WACommon.SubProtocol headerImage = 14;
|
||||
string headerTitle = 15;
|
||||
OverlayIconGlyph overlayIconGlyph = 16;
|
||||
string overlayTitle = 17;
|
||||
string overlayDescription = 18;
|
||||
string sentWithMessageID = 19;
|
||||
string messageText = 20;
|
||||
string headerSubtitle = 21;
|
||||
string xmaDataclass = 22;
|
||||
string contentRef = 23;
|
||||
}
|
469
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCert/WACert.pb.go
vendored
Normal file
469
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCert/WACert.pb.go
vendored
Normal file
@ -0,0 +1,469 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v3.21.12
|
||||
// source: waCert/WACert.proto
|
||||
|
||||
package waCert
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type NoiseCertificate struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Details []byte `protobuf:"bytes,1,opt,name=details,proto3" json:"details,omitempty"`
|
||||
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate) Reset() {
|
||||
*x = NoiseCertificate{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NoiseCertificate) ProtoMessage() {}
|
||||
|
||||
func (x *NoiseCertificate) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NoiseCertificate.ProtoReflect.Descriptor instead.
|
||||
func (*NoiseCertificate) Descriptor() ([]byte, []int) {
|
||||
return file_waCert_WACert_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate) GetDetails() []byte {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate) GetSignature() []byte {
|
||||
if x != nil {
|
||||
return x.Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CertChain struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Leaf *CertChain_NoiseCertificate `protobuf:"bytes,1,opt,name=leaf,proto3" json:"leaf,omitempty"`
|
||||
Intermediate *CertChain_NoiseCertificate `protobuf:"bytes,2,opt,name=intermediate,proto3" json:"intermediate,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CertChain) Reset() {
|
||||
*x = CertChain{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CertChain) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CertChain) ProtoMessage() {}
|
||||
|
||||
func (x *CertChain) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CertChain.ProtoReflect.Descriptor instead.
|
||||
func (*CertChain) Descriptor() ([]byte, []int) {
|
||||
return file_waCert_WACert_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *CertChain) GetLeaf() *CertChain_NoiseCertificate {
|
||||
if x != nil {
|
||||
return x.Leaf
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CertChain) GetIntermediate() *CertChain_NoiseCertificate {
|
||||
if x != nil {
|
||||
return x.Intermediate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NoiseCertificate_Details struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Serial uint32 `protobuf:"varint,1,opt,name=serial,proto3" json:"serial,omitempty"`
|
||||
Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"`
|
||||
Expires uint64 `protobuf:"varint,3,opt,name=expires,proto3" json:"expires,omitempty"`
|
||||
Subject string `protobuf:"bytes,4,opt,name=subject,proto3" json:"subject,omitempty"`
|
||||
Key []byte `protobuf:"bytes,5,opt,name=key,proto3" json:"key,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate_Details) Reset() {
|
||||
*x = NoiseCertificate_Details{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate_Details) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NoiseCertificate_Details) ProtoMessage() {}
|
||||
|
||||
func (x *NoiseCertificate_Details) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use NoiseCertificate_Details.ProtoReflect.Descriptor instead.
|
||||
func (*NoiseCertificate_Details) Descriptor() ([]byte, []int) {
|
||||
return file_waCert_WACert_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate_Details) GetSerial() uint32 {
|
||||
if x != nil {
|
||||
return x.Serial
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate_Details) GetIssuer() string {
|
||||
if x != nil {
|
||||
return x.Issuer
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate_Details) GetExpires() uint64 {
|
||||
if x != nil {
|
||||
return x.Expires
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate_Details) GetSubject() string {
|
||||
if x != nil {
|
||||
return x.Subject
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NoiseCertificate_Details) GetKey() []byte {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CertChain_NoiseCertificate struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Details []byte `protobuf:"bytes,1,opt,name=details,proto3" json:"details,omitempty"`
|
||||
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate) Reset() {
|
||||
*x = CertChain_NoiseCertificate{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CertChain_NoiseCertificate) ProtoMessage() {}
|
||||
|
||||
func (x *CertChain_NoiseCertificate) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CertChain_NoiseCertificate.ProtoReflect.Descriptor instead.
|
||||
func (*CertChain_NoiseCertificate) Descriptor() ([]byte, []int) {
|
||||
return file_waCert_WACert_proto_rawDescGZIP(), []int{1, 0}
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate) GetDetails() []byte {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate) GetSignature() []byte {
|
||||
if x != nil {
|
||||
return x.Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CertChain_NoiseCertificate_Details struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Serial uint32 `protobuf:"varint,1,opt,name=serial,proto3" json:"serial,omitempty"`
|
||||
IssuerSerial uint32 `protobuf:"varint,2,opt,name=issuerSerial,proto3" json:"issuerSerial,omitempty"`
|
||||
Key []byte `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
|
||||
NotBefore uint64 `protobuf:"varint,4,opt,name=notBefore,proto3" json:"notBefore,omitempty"`
|
||||
NotAfter uint64 `protobuf:"varint,5,opt,name=notAfter,proto3" json:"notAfter,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate_Details) Reset() {
|
||||
*x = CertChain_NoiseCertificate_Details{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate_Details) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CertChain_NoiseCertificate_Details) ProtoMessage() {}
|
||||
|
||||
func (x *CertChain_NoiseCertificate_Details) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCert_WACert_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CertChain_NoiseCertificate_Details.ProtoReflect.Descriptor instead.
|
||||
func (*CertChain_NoiseCertificate_Details) Descriptor() ([]byte, []int) {
|
||||
return file_waCert_WACert_proto_rawDescGZIP(), []int{1, 0, 0}
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate_Details) GetSerial() uint32 {
|
||||
if x != nil {
|
||||
return x.Serial
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate_Details) GetIssuerSerial() uint32 {
|
||||
if x != nil {
|
||||
return x.IssuerSerial
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate_Details) GetKey() []byte {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate_Details) GetNotBefore() uint64 {
|
||||
if x != nil {
|
||||
return x.NotBefore
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CertChain_NoiseCertificate_Details) GetNotAfter() uint64 {
|
||||
if x != nil {
|
||||
return x.NotAfter
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_waCert_WACert_proto protoreflect.FileDescriptor
|
||||
|
||||
//go:embed WACert.pb.raw
|
||||
var file_waCert_WACert_proto_rawDesc []byte
|
||||
|
||||
var (
|
||||
file_waCert_WACert_proto_rawDescOnce sync.Once
|
||||
file_waCert_WACert_proto_rawDescData = file_waCert_WACert_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_waCert_WACert_proto_rawDescGZIP() []byte {
|
||||
file_waCert_WACert_proto_rawDescOnce.Do(func() {
|
||||
file_waCert_WACert_proto_rawDescData = protoimpl.X.CompressGZIP(file_waCert_WACert_proto_rawDescData)
|
||||
})
|
||||
return file_waCert_WACert_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_waCert_WACert_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_waCert_WACert_proto_goTypes = []interface{}{
|
||||
(*NoiseCertificate)(nil), // 0: WACert.NoiseCertificate
|
||||
(*CertChain)(nil), // 1: WACert.CertChain
|
||||
(*NoiseCertificate_Details)(nil), // 2: WACert.NoiseCertificate.Details
|
||||
(*CertChain_NoiseCertificate)(nil), // 3: WACert.CertChain.NoiseCertificate
|
||||
(*CertChain_NoiseCertificate_Details)(nil), // 4: WACert.CertChain.NoiseCertificate.Details
|
||||
}
|
||||
var file_waCert_WACert_proto_depIdxs = []int32{
|
||||
3, // 0: WACert.CertChain.leaf:type_name -> WACert.CertChain.NoiseCertificate
|
||||
3, // 1: WACert.CertChain.intermediate:type_name -> WACert.CertChain.NoiseCertificate
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_waCert_WACert_proto_init() }
|
||||
func file_waCert_WACert_proto_init() {
|
||||
if File_waCert_WACert_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_waCert_WACert_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NoiseCertificate); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waCert_WACert_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CertChain); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waCert_WACert_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NoiseCertificate_Details); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waCert_WACert_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CertChain_NoiseCertificate); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waCert_WACert_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CertChain_NoiseCertificate_Details); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_waCert_WACert_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_waCert_WACert_proto_goTypes,
|
||||
DependencyIndexes: file_waCert_WACert_proto_depIdxs,
|
||||
MessageInfos: file_waCert_WACert_proto_msgTypes,
|
||||
}.Build()
|
||||
File_waCert_WACert_proto = out.File
|
||||
file_waCert_WACert_proto_rawDesc = nil
|
||||
file_waCert_WACert_proto_goTypes = nil
|
||||
file_waCert_WACert_proto_depIdxs = nil
|
||||
}
|
23
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCert/WACert.pb.raw
vendored
Normal file
23
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCert/WACert.pb.raw
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
waCert/WACert.protoWACert"Ë
|
||||
NoiseCertificate
|
||||
details (Rdetails
|
||||
signature (R signature
|
||||
Details
|
||||
serial (
Rserial
|
||||
issuer ( Rissuer
|
||||
expires (Rexpires
|
||||
subject ( Rsubject
|
||||
key (Rkey"ì
|
||||
CertChain6
|
||||
leaf (2".WACert.CertChain.NoiseCertificateRleafF
|
||||
intermediate (2".WACert.CertChain.NoiseCertificateRintermediateÞ
|
||||
NoiseCertificate
|
||||
details (Rdetails
|
||||
signature (R signature‘
|
||||
Details
|
||||
serial (
Rserial"
|
||||
issuerSerial (
RissuerSerial
|
||||
key (Rkey
|
||||
notBefore (R notBefore
|
||||
notAfter (RnotAfterB-Z+go.mau.fi/whatsmeow/binary/armadillo/waCertbproto3
|
34
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCert/WACert.proto
vendored
Normal file
34
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCert/WACert.proto
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
syntax = "proto3";
|
||||
package WACert;
|
||||
option go_package = "go.mau.fi/whatsmeow/binary/armadillo/waCert";
|
||||
|
||||
message NoiseCertificate {
|
||||
message Details {
|
||||
uint32 serial = 1;
|
||||
string issuer = 2;
|
||||
uint64 expires = 3;
|
||||
string subject = 4;
|
||||
bytes key = 5;
|
||||
}
|
||||
|
||||
bytes details = 1;
|
||||
bytes signature = 2;
|
||||
}
|
||||
|
||||
message CertChain {
|
||||
message NoiseCertificate {
|
||||
message Details {
|
||||
uint32 serial = 1;
|
||||
uint32 issuerSerial = 2;
|
||||
bytes key = 3;
|
||||
uint64 notBefore = 4;
|
||||
uint64 notAfter = 5;
|
||||
}
|
||||
|
||||
bytes details = 1;
|
||||
bytes signature = 2;
|
||||
}
|
||||
|
||||
NoiseCertificate leaf = 1;
|
||||
NoiseCertificate intermediate = 2;
|
||||
}
|
498
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCommon/WACommon.pb.go
vendored
Normal file
498
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCommon/WACommon.pb.go
vendored
Normal file
@ -0,0 +1,498 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v3.21.12
|
||||
// source: waCommon/WACommon.proto
|
||||
|
||||
package waCommon
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type FutureProofBehavior int32
|
||||
|
||||
const (
|
||||
FutureProofBehavior_PLACEHOLDER FutureProofBehavior = 0
|
||||
FutureProofBehavior_NO_PLACEHOLDER FutureProofBehavior = 1
|
||||
FutureProofBehavior_IGNORE FutureProofBehavior = 2
|
||||
)
|
||||
|
||||
// Enum value maps for FutureProofBehavior.
|
||||
var (
|
||||
FutureProofBehavior_name = map[int32]string{
|
||||
0: "PLACEHOLDER",
|
||||
1: "NO_PLACEHOLDER",
|
||||
2: "IGNORE",
|
||||
}
|
||||
FutureProofBehavior_value = map[string]int32{
|
||||
"PLACEHOLDER": 0,
|
||||
"NO_PLACEHOLDER": 1,
|
||||
"IGNORE": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x FutureProofBehavior) Enum() *FutureProofBehavior {
|
||||
p := new(FutureProofBehavior)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x FutureProofBehavior) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (FutureProofBehavior) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_waCommon_WACommon_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (FutureProofBehavior) Type() protoreflect.EnumType {
|
||||
return &file_waCommon_WACommon_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x FutureProofBehavior) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FutureProofBehavior.Descriptor instead.
|
||||
func (FutureProofBehavior) EnumDescriptor() ([]byte, []int) {
|
||||
return file_waCommon_WACommon_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type Command_CommandType int32
|
||||
|
||||
const (
|
||||
Command_COMMANDTYPE_UNKNOWN Command_CommandType = 0
|
||||
Command_EVERYONE Command_CommandType = 1
|
||||
Command_SILENT Command_CommandType = 2
|
||||
Command_AI Command_CommandType = 3
|
||||
)
|
||||
|
||||
// Enum value maps for Command_CommandType.
|
||||
var (
|
||||
Command_CommandType_name = map[int32]string{
|
||||
0: "COMMANDTYPE_UNKNOWN",
|
||||
1: "EVERYONE",
|
||||
2: "SILENT",
|
||||
3: "AI",
|
||||
}
|
||||
Command_CommandType_value = map[string]int32{
|
||||
"COMMANDTYPE_UNKNOWN": 0,
|
||||
"EVERYONE": 1,
|
||||
"SILENT": 2,
|
||||
"AI": 3,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Command_CommandType) Enum() *Command_CommandType {
|
||||
p := new(Command_CommandType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Command_CommandType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Command_CommandType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_waCommon_WACommon_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (Command_CommandType) Type() protoreflect.EnumType {
|
||||
return &file_waCommon_WACommon_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x Command_CommandType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Command_CommandType.Descriptor instead.
|
||||
func (Command_CommandType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_waCommon_WACommon_proto_rawDescGZIP(), []int{1, 0}
|
||||
}
|
||||
|
||||
type MessageKey struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
RemoteJID string `protobuf:"bytes,1,opt,name=remoteJID,proto3" json:"remoteJID,omitempty"`
|
||||
FromMe bool `protobuf:"varint,2,opt,name=fromMe,proto3" json:"fromMe,omitempty"`
|
||||
ID string `protobuf:"bytes,3,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
Participant string `protobuf:"bytes,4,opt,name=participant,proto3" json:"participant,omitempty"`
|
||||
}
|
||||
|
||||
func (x *MessageKey) Reset() {
|
||||
*x = MessageKey{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCommon_WACommon_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *MessageKey) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*MessageKey) ProtoMessage() {}
|
||||
|
||||
func (x *MessageKey) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCommon_WACommon_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MessageKey.ProtoReflect.Descriptor instead.
|
||||
func (*MessageKey) Descriptor() ([]byte, []int) {
|
||||
return file_waCommon_WACommon_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *MessageKey) GetRemoteJID() string {
|
||||
if x != nil {
|
||||
return x.RemoteJID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MessageKey) GetFromMe() bool {
|
||||
if x != nil {
|
||||
return x.FromMe
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *MessageKey) GetID() string {
|
||||
if x != nil {
|
||||
return x.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MessageKey) GetParticipant() string {
|
||||
if x != nil {
|
||||
return x.Participant
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Command struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
CommandType Command_CommandType `protobuf:"varint,1,opt,name=commandType,proto3,enum=WACommon.Command_CommandType" json:"commandType,omitempty"`
|
||||
Offset uint32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
Length uint32 `protobuf:"varint,3,opt,name=length,proto3" json:"length,omitempty"`
|
||||
ValidationToken string `protobuf:"bytes,4,opt,name=validationToken,proto3" json:"validationToken,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Command) Reset() {
|
||||
*x = Command{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCommon_WACommon_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Command) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Command) ProtoMessage() {}
|
||||
|
||||
func (x *Command) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCommon_WACommon_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Command.ProtoReflect.Descriptor instead.
|
||||
func (*Command) Descriptor() ([]byte, []int) {
|
||||
return file_waCommon_WACommon_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Command) GetCommandType() Command_CommandType {
|
||||
if x != nil {
|
||||
return x.CommandType
|
||||
}
|
||||
return Command_COMMANDTYPE_UNKNOWN
|
||||
}
|
||||
|
||||
func (x *Command) GetOffset() uint32 {
|
||||
if x != nil {
|
||||
return x.Offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Command) GetLength() uint32 {
|
||||
if x != nil {
|
||||
return x.Length
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Command) GetValidationToken() string {
|
||||
if x != nil {
|
||||
return x.ValidationToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type MessageText struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"`
|
||||
MentionedJID []string `protobuf:"bytes,2,rep,name=mentionedJID,proto3" json:"mentionedJID,omitempty"`
|
||||
Commands []*Command `protobuf:"bytes,3,rep,name=commands,proto3" json:"commands,omitempty"`
|
||||
}
|
||||
|
||||
func (x *MessageText) Reset() {
|
||||
*x = MessageText{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCommon_WACommon_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *MessageText) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*MessageText) ProtoMessage() {}
|
||||
|
||||
func (x *MessageText) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCommon_WACommon_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MessageText.ProtoReflect.Descriptor instead.
|
||||
func (*MessageText) Descriptor() ([]byte, []int) {
|
||||
return file_waCommon_WACommon_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *MessageText) GetText() string {
|
||||
if x != nil {
|
||||
return x.Text
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MessageText) GetMentionedJID() []string {
|
||||
if x != nil {
|
||||
return x.MentionedJID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *MessageText) GetCommands() []*Command {
|
||||
if x != nil {
|
||||
return x.Commands
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SubProtocol struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
Version int32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SubProtocol) Reset() {
|
||||
*x = SubProtocol{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_waCommon_WACommon_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SubProtocol) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SubProtocol) ProtoMessage() {}
|
||||
|
||||
func (x *SubProtocol) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_waCommon_WACommon_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SubProtocol.ProtoReflect.Descriptor instead.
|
||||
func (*SubProtocol) Descriptor() ([]byte, []int) {
|
||||
return file_waCommon_WACommon_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *SubProtocol) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SubProtocol) GetVersion() int32 {
|
||||
if x != nil {
|
||||
return x.Version
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_waCommon_WACommon_proto protoreflect.FileDescriptor
|
||||
|
||||
//go:embed WACommon.pb.raw
|
||||
var file_waCommon_WACommon_proto_rawDesc []byte
|
||||
|
||||
var (
|
||||
file_waCommon_WACommon_proto_rawDescOnce sync.Once
|
||||
file_waCommon_WACommon_proto_rawDescData = file_waCommon_WACommon_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_waCommon_WACommon_proto_rawDescGZIP() []byte {
|
||||
file_waCommon_WACommon_proto_rawDescOnce.Do(func() {
|
||||
file_waCommon_WACommon_proto_rawDescData = protoimpl.X.CompressGZIP(file_waCommon_WACommon_proto_rawDescData)
|
||||
})
|
||||
return file_waCommon_WACommon_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_waCommon_WACommon_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_waCommon_WACommon_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_waCommon_WACommon_proto_goTypes = []interface{}{
|
||||
(FutureProofBehavior)(0), // 0: WACommon.FutureProofBehavior
|
||||
(Command_CommandType)(0), // 1: WACommon.Command.CommandType
|
||||
(*MessageKey)(nil), // 2: WACommon.MessageKey
|
||||
(*Command)(nil), // 3: WACommon.Command
|
||||
(*MessageText)(nil), // 4: WACommon.MessageText
|
||||
(*SubProtocol)(nil), // 5: WACommon.SubProtocol
|
||||
}
|
||||
var file_waCommon_WACommon_proto_depIdxs = []int32{
|
||||
1, // 0: WACommon.Command.commandType:type_name -> WACommon.Command.CommandType
|
||||
3, // 1: WACommon.MessageText.commands:type_name -> WACommon.Command
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_waCommon_WACommon_proto_init() }
|
||||
func file_waCommon_WACommon_proto_init() {
|
||||
if File_waCommon_WACommon_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_waCommon_WACommon_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*MessageKey); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waCommon_WACommon_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Command); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waCommon_WACommon_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*MessageText); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_waCommon_WACommon_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SubProtocol); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_waCommon_WACommon_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_waCommon_WACommon_proto_goTypes,
|
||||
DependencyIndexes: file_waCommon_WACommon_proto_depIdxs,
|
||||
EnumInfos: file_waCommon_WACommon_proto_enumTypes,
|
||||
MessageInfos: file_waCommon_WACommon_proto_msgTypes,
|
||||
}.Build()
|
||||
File_waCommon_WACommon_proto = out.File
|
||||
file_waCommon_WACommon_proto_rawDesc = nil
|
||||
file_waCommon_WACommon_proto_goTypes = nil
|
||||
file_waCommon_WACommon_proto_depIdxs = nil
|
||||
}
|
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCommon/WACommon.pb.raw
vendored
Normal file
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCommon/WACommon.pb.raw
vendored
Normal file
Binary file not shown.
41
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCommon/WACommon.proto
vendored
Normal file
41
vendor/go.mau.fi/whatsmeow/binary/armadillo/waCommon/WACommon.proto
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
syntax = "proto3";
|
||||
package WACommon;
|
||||
option go_package = "go.mau.fi/whatsmeow/binary/armadillo/waCommon";
|
||||
|
||||
enum FutureProofBehavior {
|
||||
PLACEHOLDER = 0;
|
||||
NO_PLACEHOLDER = 1;
|
||||
IGNORE = 2;
|
||||
}
|
||||
|
||||
message MessageKey {
|
||||
string remoteJID = 1;
|
||||
bool fromMe = 2;
|
||||
string ID = 3;
|
||||
string participant = 4;
|
||||
}
|
||||
|
||||
message Command {
|
||||
enum CommandType {
|
||||
COMMANDTYPE_UNKNOWN = 0;
|
||||
EVERYONE = 1;
|
||||
SILENT = 2;
|
||||
AI = 3;
|
||||
}
|
||||
|
||||
CommandType commandType = 1;
|
||||
uint32 offset = 2;
|
||||
uint32 length = 3;
|
||||
string validationToken = 4;
|
||||
}
|
||||
|
||||
message MessageText {
|
||||
string text = 1;
|
||||
repeated string mentionedJID = 2;
|
||||
repeated Command commands = 3;
|
||||
}
|
||||
|
||||
message SubProtocol {
|
||||
bytes payload = 1;
|
||||
int32 version = 2;
|
||||
}
|
3069
vendor/go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication/WAConsumerApplication.pb.go
vendored
Normal file
3069
vendor/go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication/WAConsumerApplication.pb.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication/WAConsumerApplication.pb.raw
vendored
Normal file
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication/WAConsumerApplication.pb.raw
vendored
Normal file
Binary file not shown.
234
vendor/go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication/WAConsumerApplication.proto
vendored
Normal file
234
vendor/go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication/WAConsumerApplication.proto
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
syntax = "proto3";
|
||||
package WAConsumerApplication;
|
||||
option go_package = "go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication";
|
||||
|
||||
import "waCommon/WACommon.proto";
|
||||
|
||||
message ConsumerApplication {
|
||||
message Payload {
|
||||
oneof payload {
|
||||
Content content = 1;
|
||||
ApplicationData applicationData = 2;
|
||||
Signal signal = 3;
|
||||
SubProtocolPayload subProtocol = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message SubProtocolPayload {
|
||||
WACommon.FutureProofBehavior futureProof = 1;
|
||||
}
|
||||
|
||||
message Metadata {
|
||||
enum SpecialTextSize {
|
||||
SPECIALTEXTSIZE_UNKNOWN = 0;
|
||||
SMALL = 1;
|
||||
MEDIUM = 2;
|
||||
LARGE = 3;
|
||||
}
|
||||
|
||||
SpecialTextSize specialTextSize = 1;
|
||||
}
|
||||
|
||||
message Signal {
|
||||
}
|
||||
|
||||
message ApplicationData {
|
||||
oneof applicationContent {
|
||||
RevokeMessage revoke = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message Content {
|
||||
oneof content {
|
||||
WACommon.MessageText messageText = 1;
|
||||
ImageMessage imageMessage = 2;
|
||||
ContactMessage contactMessage = 3;
|
||||
LocationMessage locationMessage = 4;
|
||||
ExtendedTextMessage extendedTextMessage = 5;
|
||||
StatusTextMesage statusTextMessage = 6;
|
||||
DocumentMessage documentMessage = 7;
|
||||
AudioMessage audioMessage = 8;
|
||||
VideoMessage videoMessage = 9;
|
||||
ContactsArrayMessage contactsArrayMessage = 10;
|
||||
LiveLocationMessage liveLocationMessage = 11;
|
||||
StickerMessage stickerMessage = 12;
|
||||
GroupInviteMessage groupInviteMessage = 13;
|
||||
ViewOnceMessage viewOnceMessage = 14;
|
||||
ReactionMessage reactionMessage = 16;
|
||||
PollCreationMessage pollCreationMessage = 17;
|
||||
PollUpdateMessage pollUpdateMessage = 18;
|
||||
EditMessage editMessage = 19;
|
||||
}
|
||||
}
|
||||
|
||||
message EditMessage {
|
||||
WACommon.MessageKey key = 1;
|
||||
WACommon.MessageText message = 2;
|
||||
int64 timestampMS = 3;
|
||||
}
|
||||
|
||||
message PollAddOptionMessage {
|
||||
repeated Option pollOption = 1;
|
||||
}
|
||||
|
||||
message PollVoteMessage {
|
||||
repeated bytes selectedOptions = 1;
|
||||
int64 senderTimestampMS = 2;
|
||||
}
|
||||
|
||||
message PollEncValue {
|
||||
bytes encPayload = 1;
|
||||
bytes encIV = 2;
|
||||
}
|
||||
|
||||
message PollUpdateMessage {
|
||||
WACommon.MessageKey pollCreationMessageKey = 1;
|
||||
PollEncValue vote = 2;
|
||||
PollEncValue addOption = 3;
|
||||
}
|
||||
|
||||
message PollCreationMessage {
|
||||
bytes encKey = 1;
|
||||
string name = 2;
|
||||
repeated Option options = 3;
|
||||
uint32 selectableOptionsCount = 4;
|
||||
}
|
||||
|
||||
message Option {
|
||||
string optionName = 1;
|
||||
}
|
||||
|
||||
message ReactionMessage {
|
||||
WACommon.MessageKey key = 1;
|
||||
string text = 2;
|
||||
string groupingKey = 3;
|
||||
int64 senderTimestampMS = 4;
|
||||
string reactionMetadataDataclassData = 5;
|
||||
int32 style = 6;
|
||||
}
|
||||
|
||||
message RevokeMessage {
|
||||
WACommon.MessageKey key = 1;
|
||||
}
|
||||
|
||||
message ViewOnceMessage {
|
||||
oneof viewOnceContent {
|
||||
ImageMessage imageMessage = 1;
|
||||
VideoMessage videoMessage = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message GroupInviteMessage {
|
||||
string groupJID = 1;
|
||||
string inviteCode = 2;
|
||||
int64 inviteExpiration = 3;
|
||||
string groupName = 4;
|
||||
bytes JPEGThumbnail = 5;
|
||||
WACommon.MessageText caption = 6;
|
||||
}
|
||||
|
||||
message LiveLocationMessage {
|
||||
Location location = 1;
|
||||
uint32 accuracyInMeters = 2;
|
||||
float speedInMps = 3;
|
||||
uint32 degreesClockwiseFromMagneticNorth = 4;
|
||||
WACommon.MessageText caption = 5;
|
||||
int64 sequenceNumber = 6;
|
||||
uint32 timeOffset = 7;
|
||||
}
|
||||
|
||||
message ContactsArrayMessage {
|
||||
string displayName = 1;
|
||||
repeated ContactMessage contacts = 2;
|
||||
}
|
||||
|
||||
message ContactMessage {
|
||||
WACommon.SubProtocol contact = 1;
|
||||
}
|
||||
|
||||
message StatusTextMesage {
|
||||
enum FontType {
|
||||
SANS_SERIF = 0;
|
||||
SERIF = 1;
|
||||
NORICAN_REGULAR = 2;
|
||||
BRYNDAN_WRITE = 3;
|
||||
BEBASNEUE_REGULAR = 4;
|
||||
OSWALD_HEAVY = 5;
|
||||
}
|
||||
|
||||
ExtendedTextMessage text = 1;
|
||||
fixed32 textArgb = 6;
|
||||
fixed32 backgroundArgb = 7;
|
||||
FontType font = 8;
|
||||
}
|
||||
|
||||
message ExtendedTextMessage {
|
||||
enum PreviewType {
|
||||
NONE = 0;
|
||||
VIDEO = 1;
|
||||
}
|
||||
|
||||
WACommon.MessageText text = 1;
|
||||
string matchedText = 2;
|
||||
string canonicalURL = 3;
|
||||
string description = 4;
|
||||
string title = 5;
|
||||
WACommon.SubProtocol thumbnail = 6;
|
||||
PreviewType previewType = 7;
|
||||
}
|
||||
|
||||
message LocationMessage {
|
||||
Location location = 1;
|
||||
string address = 2;
|
||||
}
|
||||
|
||||
message StickerMessage {
|
||||
WACommon.SubProtocol sticker = 1;
|
||||
}
|
||||
|
||||
message DocumentMessage {
|
||||
WACommon.SubProtocol document = 1;
|
||||
string fileName = 2;
|
||||
}
|
||||
|
||||
message VideoMessage {
|
||||
WACommon.SubProtocol video = 1;
|
||||
WACommon.MessageText caption = 2;
|
||||
}
|
||||
|
||||
message AudioMessage {
|
||||
WACommon.SubProtocol audio = 1;
|
||||
bool PTT = 2;
|
||||
}
|
||||
|
||||
message ImageMessage {
|
||||
WACommon.SubProtocol image = 1;
|
||||
WACommon.MessageText caption = 2;
|
||||
}
|
||||
|
||||
message InteractiveAnnotation {
|
||||
oneof action {
|
||||
Location location = 2;
|
||||
}
|
||||
|
||||
repeated Point polygonVertices = 1;
|
||||
}
|
||||
|
||||
message Point {
|
||||
double x = 1;
|
||||
double y = 2;
|
||||
}
|
||||
|
||||
message Location {
|
||||
double degreesLatitude = 1;
|
||||
double degreesLongitude = 2;
|
||||
string name = 3;
|
||||
}
|
||||
|
||||
message MediaPayload {
|
||||
WACommon.SubProtocol protocol = 1;
|
||||
}
|
||||
|
||||
Payload payload = 1;
|
||||
Metadata metadata = 2;
|
||||
}
|
82
vendor/go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication/extra.go
vendored
Normal file
82
vendor/go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication/extra.go
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
package waConsumerApplication
|
||||
|
||||
import (
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/armadilloutil"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMediaTransport"
|
||||
)
|
||||
|
||||
type ConsumerApplication_Content_Content = isConsumerApplication_Content_Content
|
||||
|
||||
func (*ConsumerApplication) IsMessageApplicationSub() {}
|
||||
|
||||
const (
|
||||
ImageTransportVersion = 1
|
||||
StickerTransportVersion = 1
|
||||
VideoTransportVersion = 1
|
||||
AudioTransportVersion = 1
|
||||
DocumentTransportVersion = 1
|
||||
ContactTransportVersion = 1
|
||||
)
|
||||
|
||||
func (msg *ConsumerApplication_ImageMessage) Decode() (dec *waMediaTransport.ImageTransport, err error) {
|
||||
return armadilloutil.Unmarshal(&waMediaTransport.ImageTransport{}, msg.GetImage(), ImageTransportVersion)
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_ImageMessage) Set(payload *waMediaTransport.ImageTransport) (err error) {
|
||||
msg.Image, err = armadilloutil.Marshal(payload, ImageTransportVersion)
|
||||
return
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_StickerMessage) Decode() (dec *waMediaTransport.StickerTransport, err error) {
|
||||
return armadilloutil.Unmarshal(&waMediaTransport.StickerTransport{}, msg.GetSticker(), StickerTransportVersion)
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_StickerMessage) Set(payload *waMediaTransport.StickerTransport) (err error) {
|
||||
msg.Sticker, err = armadilloutil.Marshal(payload, StickerTransportVersion)
|
||||
return
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_ExtendedTextMessage) DecodeThumbnail() (dec *waMediaTransport.ImageTransport, err error) {
|
||||
return armadilloutil.Unmarshal(&waMediaTransport.ImageTransport{}, msg.GetThumbnail(), ImageTransportVersion)
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_ExtendedTextMessage) SetThumbnail(payload *waMediaTransport.ImageTransport) (err error) {
|
||||
msg.Thumbnail, err = armadilloutil.Marshal(payload, ImageTransportVersion)
|
||||
return
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_VideoMessage) Decode() (dec *waMediaTransport.VideoTransport, err error) {
|
||||
return armadilloutil.Unmarshal(&waMediaTransport.VideoTransport{}, msg.GetVideo(), VideoTransportVersion)
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_VideoMessage) Set(payload *waMediaTransport.VideoTransport) (err error) {
|
||||
msg.Video, err = armadilloutil.Marshal(payload, VideoTransportVersion)
|
||||
return
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_AudioMessage) Decode() (dec *waMediaTransport.AudioTransport, err error) {
|
||||
return armadilloutil.Unmarshal(&waMediaTransport.AudioTransport{}, msg.GetAudio(), AudioTransportVersion)
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_AudioMessage) Set(payload *waMediaTransport.AudioTransport) (err error) {
|
||||
msg.Audio, err = armadilloutil.Marshal(payload, AudioTransportVersion)
|
||||
return
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_DocumentMessage) Decode() (dec *waMediaTransport.DocumentTransport, err error) {
|
||||
return armadilloutil.Unmarshal(&waMediaTransport.DocumentTransport{}, msg.GetDocument(), DocumentTransportVersion)
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_DocumentMessage) Set(payload *waMediaTransport.DocumentTransport) (err error) {
|
||||
msg.Document, err = armadilloutil.Marshal(payload, DocumentTransportVersion)
|
||||
return
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_ContactMessage) Decode() (dec *waMediaTransport.ContactTransport, err error) {
|
||||
return armadilloutil.Unmarshal(&waMediaTransport.ContactTransport{}, msg.GetContact(), ContactTransportVersion)
|
||||
}
|
||||
|
||||
func (msg *ConsumerApplication_ContactMessage) Set(payload *waMediaTransport.ContactTransport) (err error) {
|
||||
msg.Contact, err = armadilloutil.Marshal(payload, ContactTransportVersion)
|
||||
return
|
||||
}
|
16792
vendor/go.mau.fi/whatsmeow/binary/armadillo/waE2E/WAE2E.pb.go
vendored
Normal file
16792
vendor/go.mau.fi/whatsmeow/binary/armadillo/waE2E/WAE2E.pb.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waE2E/WAE2E.pb.raw
vendored
Normal file
BIN
vendor/go.mau.fi/whatsmeow/binary/armadillo/waE2E/WAE2E.pb.raw
vendored
Normal file
Binary file not shown.
18
vendor/go.mau.fi/whatsmeow/call.go
vendored
18
vendor/go.mau.fi/whatsmeow/call.go
vendored
@ -59,6 +59,24 @@ func (cli *Client) handleCallEvent(node *waBinary.Node) {
|
||||
},
|
||||
Data: &child,
|
||||
})
|
||||
case "preaccept":
|
||||
cli.dispatchEvent(&events.CallPreAccept{
|
||||
BasicCallMeta: basicMeta,
|
||||
CallRemoteMeta: types.CallRemoteMeta{
|
||||
RemotePlatform: ag.String("platform"),
|
||||
RemoteVersion: ag.String("version"),
|
||||
},
|
||||
Data: &child,
|
||||
})
|
||||
case "transport":
|
||||
cli.dispatchEvent(&events.CallTransport{
|
||||
BasicCallMeta: basicMeta,
|
||||
CallRemoteMeta: types.CallRemoteMeta{
|
||||
RemotePlatform: ag.String("platform"),
|
||||
RemoteVersion: ag.String("version"),
|
||||
},
|
||||
Data: &child,
|
||||
})
|
||||
case "terminate":
|
||||
cli.dispatchEvent(&events.CallTerminate{
|
||||
BasicCallMeta: basicMeta,
|
||||
|
180
vendor/go.mau.fi/whatsmeow/client.go
vendored
180
vendor/go.mau.fi/whatsmeow/client.go
vendored
@ -19,6 +19,10 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"go.mau.fi/util/random"
|
||||
"golang.org/x/net/proxy"
|
||||
|
||||
"go.mau.fi/whatsmeow/appstate"
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
@ -28,7 +32,6 @@ import (
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
"go.mau.fi/whatsmeow/util/keys"
|
||||
waLog "go.mau.fi/whatsmeow/util/log"
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
// EventHandler is a function that can handle events from WhatsApp.
|
||||
@ -42,6 +45,11 @@ type wrappedEventHandler struct {
|
||||
id uint32
|
||||
}
|
||||
|
||||
type deviceCache struct {
|
||||
devices []types.JID
|
||||
dhash string
|
||||
}
|
||||
|
||||
// Client contains everything necessary to connect to and interact with the WhatsApp web API.
|
||||
type Client struct {
|
||||
Store *store.Device
|
||||
@ -53,13 +61,16 @@ type Client struct {
|
||||
socketLock sync.RWMutex
|
||||
socketWait chan struct{}
|
||||
|
||||
isLoggedIn uint32
|
||||
expectedDisconnectVal uint32
|
||||
isLoggedIn atomic.Bool
|
||||
expectedDisconnect atomic.Bool
|
||||
EnableAutoReconnect bool
|
||||
LastSuccessfulConnect time.Time
|
||||
AutoReconnectErrors int
|
||||
// AutoReconnectHook is called when auto-reconnection fails. If the function returns false,
|
||||
// the client will not attempt to reconnect. The number of retries can be read from AutoReconnectErrors.
|
||||
AutoReconnectHook func(error) bool
|
||||
|
||||
sendActiveReceipts uint32
|
||||
sendActiveReceipts atomic.Uint32
|
||||
|
||||
// EmitAppStateEventsOnFullSync can be set to true if you want to get app state events emitted
|
||||
// even when re-syncing the whole state.
|
||||
@ -73,7 +84,7 @@ type Client struct {
|
||||
appStateSyncLock sync.Mutex
|
||||
|
||||
historySyncNotifications chan *waProto.HistorySyncNotification
|
||||
historySyncHandlerStarted uint32
|
||||
historySyncHandlerStarted atomic.Bool
|
||||
|
||||
uploadPreKeysLock sync.Mutex
|
||||
lastPreKeyUpload time.Time
|
||||
@ -92,6 +103,9 @@ type Client struct {
|
||||
messageRetries map[string]int
|
||||
messageRetriesLock sync.Mutex
|
||||
|
||||
incomingRetryRequestCounter map[incomingRetryKey]int
|
||||
incomingRetryRequestCounterLock sync.Mutex
|
||||
|
||||
appStateKeyRequests map[string]time.Time
|
||||
appStateKeyRequestsLock sync.RWMutex
|
||||
|
||||
@ -101,10 +115,10 @@ type Client struct {
|
||||
|
||||
groupParticipantsCache map[types.JID][]types.JID
|
||||
groupParticipantsCacheLock sync.Mutex
|
||||
userDevicesCache map[types.JID][]types.JID
|
||||
userDevicesCache map[types.JID]deviceCache
|
||||
userDevicesCacheLock sync.Mutex
|
||||
|
||||
recentMessagesMap map[recentMessageKey]*waProto.Message
|
||||
recentMessagesMap map[recentMessageKey]RecentMessage
|
||||
recentMessagesList [recentMessagesSize]recentMessageKey
|
||||
recentMessagesPtr int
|
||||
recentMessagesLock sync.RWMutex
|
||||
@ -122,6 +136,10 @@ type Client struct {
|
||||
// the client will disconnect.
|
||||
PrePairCallback func(jid types.JID, platform, businessName string) bool
|
||||
|
||||
// GetClientPayload is called to get the client payload for connecting to the server.
|
||||
// This should NOT be used for WhatsApp (to change the OS name, update fields in store.BaseClientPayload directly).
|
||||
GetClientPayload func() *waProto.ClientPayload
|
||||
|
||||
// Should untrusted identity errors be handled automatically? If true, the stored identity and existing signal
|
||||
// sessions will be removed on untrusted identity errors, and an events.IdentityChange will be dispatched.
|
||||
// If false, decrypting a message from untrusted devices will fail.
|
||||
@ -137,10 +155,25 @@ type Client struct {
|
||||
phoneLinkingCache *phoneLinkingCache
|
||||
|
||||
uniqueID string
|
||||
idCounter uint32
|
||||
idCounter atomic.Uint64
|
||||
|
||||
proxy socket.Proxy
|
||||
http *http.Client
|
||||
proxy Proxy
|
||||
socksProxy proxy.Dialer
|
||||
proxyOnlyLogin bool
|
||||
http *http.Client
|
||||
|
||||
// This field changes the client to act like a Messenger client instead of a WhatsApp one.
|
||||
//
|
||||
// Note that you cannot use a Messenger account just by setting this field, you must use a
|
||||
// separate library for all the non-e2ee-related stuff like logging in.
|
||||
// The library is currently embedded in mautrix-meta (https://github.com/mautrix/meta), but may be separated later.
|
||||
MessengerConfig *MessengerConfig
|
||||
RefreshCAT func() error
|
||||
}
|
||||
|
||||
type MessengerConfig struct {
|
||||
UserAgent string
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
// Size of buffer for the channel that all incoming XML nodes go through.
|
||||
@ -167,7 +200,7 @@ func NewClient(deviceStore *store.Device, log waLog.Logger) *Client {
|
||||
if log == nil {
|
||||
log = waLog.Noop
|
||||
}
|
||||
uniqueIDPrefix := randbytes.Make(2)
|
||||
uniqueIDPrefix := random.Bytes(2)
|
||||
cli := &Client{
|
||||
http: &http.Client{
|
||||
Transport: (http.DefaultTransport.(*http.Transport)).Clone(),
|
||||
@ -185,12 +218,14 @@ func NewClient(deviceStore *store.Device, log waLog.Logger) *Client {
|
||||
appStateProc: appstate.NewProcessor(deviceStore, log.Sub("AppState")),
|
||||
socketWait: make(chan struct{}),
|
||||
|
||||
incomingRetryRequestCounter: make(map[incomingRetryKey]int),
|
||||
|
||||
historySyncNotifications: make(chan *waProto.HistorySyncNotification, 32),
|
||||
|
||||
groupParticipantsCache: make(map[types.JID][]types.JID),
|
||||
userDevicesCache: make(map[types.JID][]types.JID),
|
||||
userDevicesCache: make(map[types.JID]deviceCache),
|
||||
|
||||
recentMessagesMap: make(map[recentMessageKey]*waProto.Message, recentMessagesSize),
|
||||
recentMessagesMap: make(map[recentMessageKey]RecentMessage, recentMessagesSize),
|
||||
sessionRecreateHistory: make(map[types.JID]time.Time),
|
||||
GetMessageForRetry: func(requester, to types.JID, id types.MessageID) *waProto.Message { return nil },
|
||||
appStateKeyRequests: make(map[string]time.Time),
|
||||
@ -218,19 +253,35 @@ func NewClient(deviceStore *store.Device, log waLog.Logger) *Client {
|
||||
return cli
|
||||
}
|
||||
|
||||
// SetProxyAddress is a helper method that parses a URL string and calls SetProxy.
|
||||
// SetProxyAddress is a helper method that parses a URL string and calls SetProxy or SetSOCKSProxy based on the URL scheme.
|
||||
//
|
||||
// Returns an error if url.Parse fails to parse the given address.
|
||||
func (cli *Client) SetProxyAddress(addr string) error {
|
||||
func (cli *Client) SetProxyAddress(addr string, opts ...SetProxyOptions) error {
|
||||
if addr == "" {
|
||||
cli.SetProxy(nil, opts...)
|
||||
return nil
|
||||
}
|
||||
parsed, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli.SetProxy(http.ProxyURL(parsed))
|
||||
if parsed.Scheme == "http" || parsed.Scheme == "https" {
|
||||
cli.SetProxy(http.ProxyURL(parsed), opts...)
|
||||
} else if parsed.Scheme == "socks5" {
|
||||
px, err := proxy.FromURL(parsed, proxy.Direct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli.SetSOCKSProxy(px, opts...)
|
||||
} else {
|
||||
return fmt.Errorf("unsupported proxy scheme %q", parsed.Scheme)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetProxy sets the proxy to use for WhatsApp web websocket connections and media uploads/downloads.
|
||||
type Proxy = func(*http.Request) (*url.URL, error)
|
||||
|
||||
// SetProxy sets a HTTP proxy to use for WhatsApp web websocket connections and media uploads/downloads.
|
||||
//
|
||||
// Must be called before Connect() to take effect in the websocket connection.
|
||||
// If you want to change the proxy after connecting, you must call Disconnect() and then Connect() again manually.
|
||||
@ -250,9 +301,59 @@ func (cli *Client) SetProxyAddress(addr string) error {
|
||||
// return mediaProxyURL, nil
|
||||
// }
|
||||
// })
|
||||
func (cli *Client) SetProxy(proxy socket.Proxy) {
|
||||
cli.proxy = proxy
|
||||
cli.http.Transport.(*http.Transport).Proxy = proxy
|
||||
func (cli *Client) SetProxy(proxy Proxy, opts ...SetProxyOptions) {
|
||||
var opt SetProxyOptions
|
||||
if len(opts) > 0 {
|
||||
opt = opts[0]
|
||||
}
|
||||
if !opt.NoWebsocket {
|
||||
cli.proxy = proxy
|
||||
cli.socksProxy = nil
|
||||
}
|
||||
if !opt.NoMedia {
|
||||
transport := cli.http.Transport.(*http.Transport)
|
||||
transport.Proxy = proxy
|
||||
transport.Dial = nil
|
||||
transport.DialContext = nil
|
||||
}
|
||||
}
|
||||
|
||||
type SetProxyOptions struct {
|
||||
// If NoWebsocket is true, the proxy won't be used for the websocket
|
||||
NoWebsocket bool
|
||||
// If NoMedia is true, the proxy won't be used for media uploads/downloads
|
||||
NoMedia bool
|
||||
}
|
||||
|
||||
// SetSOCKSProxy sets a SOCKS5 proxy to use for WhatsApp web websocket connections and media uploads/downloads.
|
||||
//
|
||||
// Same details as SetProxy apply, but using a different proxy for the websocket and media is not currently supported.
|
||||
func (cli *Client) SetSOCKSProxy(px proxy.Dialer, opts ...SetProxyOptions) {
|
||||
var opt SetProxyOptions
|
||||
if len(opts) > 0 {
|
||||
opt = opts[0]
|
||||
}
|
||||
if !opt.NoWebsocket {
|
||||
cli.socksProxy = px
|
||||
cli.proxy = nil
|
||||
}
|
||||
if !opt.NoMedia {
|
||||
transport := cli.http.Transport.(*http.Transport)
|
||||
transport.Proxy = nil
|
||||
transport.Dial = cli.socksProxy.Dial
|
||||
contextDialer, ok := cli.socksProxy.(proxy.ContextDialer)
|
||||
if ok {
|
||||
transport.DialContext = contextDialer.DialContext
|
||||
} else {
|
||||
transport.DialContext = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToggleProxyOnlyForLogin changes whether the proxy set with SetProxy or related methods
|
||||
// is only used for the pre-login websocket and not authenticated websockets.
|
||||
func (cli *Client) ToggleProxyOnlyForLogin(only bool) {
|
||||
cli.proxyOnlyLogin = only
|
||||
}
|
||||
|
||||
func (cli *Client) getSocketWaitChan() <-chan struct{} {
|
||||
@ -308,7 +409,27 @@ func (cli *Client) Connect() error {
|
||||
}
|
||||
|
||||
cli.resetExpectedDisconnect()
|
||||
fs := socket.NewFrameSocket(cli.Log.Sub("Socket"), socket.WAConnHeader, cli.proxy)
|
||||
wsDialer := websocket.Dialer{}
|
||||
if !cli.proxyOnlyLogin || cli.Store.ID == nil {
|
||||
if cli.proxy != nil {
|
||||
wsDialer.Proxy = cli.proxy
|
||||
} else if cli.socksProxy != nil {
|
||||
wsDialer.NetDial = cli.socksProxy.Dial
|
||||
contextDialer, ok := cli.socksProxy.(proxy.ContextDialer)
|
||||
if ok {
|
||||
wsDialer.NetDialContext = contextDialer.DialContext
|
||||
}
|
||||
}
|
||||
}
|
||||
fs := socket.NewFrameSocket(cli.Log.Sub("Socket"), wsDialer)
|
||||
if cli.MessengerConfig != nil {
|
||||
fs.URL = "wss://web-chat-e2ee.facebook.com/ws/chat"
|
||||
fs.HTTPHeaders.Set("Origin", cli.MessengerConfig.BaseURL)
|
||||
fs.HTTPHeaders.Set("User-Agent", cli.MessengerConfig.UserAgent)
|
||||
fs.HTTPHeaders.Set("Sec-Fetch-Dest", "empty")
|
||||
fs.HTTPHeaders.Set("Sec-Fetch-Mode", "websocket")
|
||||
fs.HTTPHeaders.Set("Sec-Fetch-Site", "cross-site")
|
||||
}
|
||||
if err := fs.Connect(); err != nil {
|
||||
fs.Close(0)
|
||||
return err
|
||||
@ -323,7 +444,7 @@ func (cli *Client) Connect() error {
|
||||
|
||||
// IsLoggedIn returns true after the client is successfully connected and authenticated on WhatsApp.
|
||||
func (cli *Client) IsLoggedIn() bool {
|
||||
return atomic.LoadUint32(&cli.isLoggedIn) == 1
|
||||
return cli.isLoggedIn.Load()
|
||||
}
|
||||
|
||||
func (cli *Client) onDisconnect(ns *socket.NoiseSocket, remote bool) {
|
||||
@ -348,15 +469,15 @@ func (cli *Client) onDisconnect(ns *socket.NoiseSocket, remote bool) {
|
||||
}
|
||||
|
||||
func (cli *Client) expectDisconnect() {
|
||||
atomic.StoreUint32(&cli.expectedDisconnectVal, 1)
|
||||
cli.expectedDisconnect.Store(true)
|
||||
}
|
||||
|
||||
func (cli *Client) resetExpectedDisconnect() {
|
||||
atomic.StoreUint32(&cli.expectedDisconnectVal, 0)
|
||||
cli.expectedDisconnect.Store(false)
|
||||
}
|
||||
|
||||
func (cli *Client) isExpectedDisconnect() bool {
|
||||
return atomic.LoadUint32(&cli.expectedDisconnectVal) == 1
|
||||
return cli.expectedDisconnect.Load()
|
||||
}
|
||||
|
||||
func (cli *Client) autoReconnect() {
|
||||
@ -374,6 +495,10 @@ func (cli *Client) autoReconnect() {
|
||||
return
|
||||
} else if err != nil {
|
||||
cli.Log.Errorf("Error reconnecting after autoreconnect sleep: %v", err)
|
||||
if cli.AutoReconnectHook != nil && !cli.AutoReconnectHook(err) {
|
||||
cli.Log.Debugf("AutoReconnectHook returned false, not reconnecting")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
@ -419,6 +544,9 @@ func (cli *Client) unlockedDisconnect() {
|
||||
// Note that this will not emit any events. The LoggedOut event is only used for external logouts
|
||||
// (triggered by the user from the main device or by WhatsApp servers).
|
||||
func (cli *Client) Logout() error {
|
||||
if cli.MessengerConfig != nil {
|
||||
return errors.New("can't logout with Messenger credentials")
|
||||
}
|
||||
ownID := cli.getOwnID()
|
||||
if ownID.IsEmpty() {
|
||||
return ErrNotLoggedIn
|
||||
@ -667,7 +795,7 @@ func (cli *Client) ParseWebMessage(chatJID types.JID, webMsg *waProto.WebMessage
|
||||
if info.Sender.IsEmpty() {
|
||||
return nil, ErrNotLoggedIn
|
||||
}
|
||||
} else if chatJID.Server == types.DefaultUserServer {
|
||||
} else if chatJID.Server == types.DefaultUserServer || chatJID.Server == types.NewsletterServer {
|
||||
info.Sender = chatJID
|
||||
} else if webMsg.GetParticipant() != "" {
|
||||
info.Sender, err = types.ParseJID(webMsg.GetParticipant())
|
||||
|
76
vendor/go.mau.fi/whatsmeow/client_test.go
vendored
Normal file
76
vendor/go.mau.fi/whatsmeow/client_test.go
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"go.mau.fi/whatsmeow"
|
||||
"go.mau.fi/whatsmeow/store/sqlstore"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
waLog "go.mau.fi/whatsmeow/util/log"
|
||||
)
|
||||
|
||||
func eventHandler(evt interface{}) {
|
||||
switch v := evt.(type) {
|
||||
case *events.Message:
|
||||
fmt.Println("Received a message!", v.Message.GetConversation())
|
||||
}
|
||||
}
|
||||
|
||||
func Example() {
|
||||
dbLog := waLog.Stdout("Database", "DEBUG", true)
|
||||
// Make sure you add appropriate DB connector imports, e.g. github.com/mattn/go-sqlite3 for SQLite
|
||||
container, err := sqlstore.New("sqlite3", "file:examplestore.db?_foreign_keys=on", dbLog)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// If you want multiple sessions, remember their JIDs and use .GetDevice(jid) or .GetAllDevices() instead.
|
||||
deviceStore, err := container.GetFirstDevice()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
clientLog := waLog.Stdout("Client", "DEBUG", true)
|
||||
client := whatsmeow.NewClient(deviceStore, clientLog)
|
||||
client.AddEventHandler(eventHandler)
|
||||
|
||||
if client.Store.ID == nil {
|
||||
// No ID stored, new login
|
||||
qrChan, _ := client.GetQRChannel(context.Background())
|
||||
err = client.Connect()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for evt := range qrChan {
|
||||
if evt.Event == "code" {
|
||||
// Render the QR code here
|
||||
// e.g. qrterminal.GenerateHalfBlock(evt.Code, qrterminal.L, os.Stdout)
|
||||
// or just manually `echo 2@... | qrencode -t ansiutf8` in a terminal
|
||||
fmt.Println("QR code:", evt.Code)
|
||||
} else {
|
||||
fmt.Println("Login event:", evt.Event)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Already logged in, just connect
|
||||
err = client.Connect()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Listen to Ctrl+C (you can also do something else that prevents the program from exiting)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
<-c
|
||||
|
||||
client.Disconnect()
|
||||
}
|
34
vendor/go.mau.fi/whatsmeow/connectionevents.go
vendored
34
vendor/go.mau.fi/whatsmeow/connectionevents.go
vendored
@ -7,7 +7,6 @@
|
||||
package whatsmeow
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
@ -17,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func (cli *Client) handleStreamError(node *waBinary.Node) {
|
||||
atomic.StoreUint32(&cli.isLoggedIn, 0)
|
||||
cli.isLoggedIn.Store(false)
|
||||
cli.clearResponseWaiters(node)
|
||||
code, _ := node.Attrs["code"].(string)
|
||||
conflict, _ := node.GetOptionalChildByTag("conflict")
|
||||
@ -48,6 +47,16 @@ func (cli *Client) handleStreamError(node *waBinary.Node) {
|
||||
// This seems to happen when the server wants to restart or something.
|
||||
// The disconnection will be emitted as an events.Disconnected and then the auto-reconnect will do its thing.
|
||||
cli.Log.Warnf("Got 503 stream error, assuming automatic reconnect will handle it")
|
||||
case cli.RefreshCAT != nil && (code == events.ConnectFailureCATInvalid.NumberString() || code == events.ConnectFailureCATExpired.NumberString()):
|
||||
cli.Log.Infof("Got %s stream error, refreshing CAT before reconnecting...", code)
|
||||
cli.socketLock.RLock()
|
||||
defer cli.socketLock.RUnlock()
|
||||
err := cli.RefreshCAT()
|
||||
if err != nil {
|
||||
cli.Log.Errorf("Failed to refresh CAT: %v", err)
|
||||
cli.expectDisconnect()
|
||||
go cli.dispatchEvent(&events.CATRefreshError{Error: err})
|
||||
}
|
||||
default:
|
||||
cli.Log.Errorf("Unknown stream error: %s", node.XMLString())
|
||||
go cli.dispatchEvent(&events.StreamError{Code: code, Raw: node})
|
||||
@ -89,9 +98,20 @@ func (cli *Client) handleConnectFailure(node *waBinary.Node) {
|
||||
willAutoReconnect = false
|
||||
case reason == events.ConnectFailureServiceUnavailable:
|
||||
// Auto-reconnect for 503s
|
||||
case reason == events.ConnectFailureCATInvalid || reason == events.ConnectFailureCATExpired:
|
||||
// Auto-reconnect when rotating CAT, lock socket to ensure refresh goes through before reconnect
|
||||
cli.socketLock.RLock()
|
||||
defer cli.socketLock.RUnlock()
|
||||
case reason == 500 && message == "biz vname fetch error":
|
||||
// These happen for business accounts randomly, also auto-reconnect
|
||||
}
|
||||
if reason == 403 {
|
||||
cli.Log.Debugf(
|
||||
"Message for 403 connect failure: %s / %s",
|
||||
ag.OptionalString("logout_message_header"),
|
||||
ag.OptionalString("logout_message_subtext"),
|
||||
)
|
||||
}
|
||||
if reason.IsLoggedOut() {
|
||||
cli.Log.Infof("Got %s connect failure, sending LoggedOut event and deleting session", reason)
|
||||
go cli.dispatchEvent(&events.LoggedOut{OnConnect: true, Reason: reason})
|
||||
@ -108,6 +128,14 @@ func (cli *Client) handleConnectFailure(node *waBinary.Node) {
|
||||
} else if reason == events.ConnectFailureClientOutdated {
|
||||
cli.Log.Errorf("Client outdated (405) connect failure (client version: %s)", store.GetWAVersion().String())
|
||||
go cli.dispatchEvent(&events.ClientOutdated{})
|
||||
} else if reason == events.ConnectFailureCATInvalid || reason == events.ConnectFailureCATExpired {
|
||||
cli.Log.Infof("Got %d/%s connect failure, refreshing CAT before reconnecting...", int(reason), message)
|
||||
err := cli.RefreshCAT()
|
||||
if err != nil {
|
||||
cli.Log.Errorf("Failed to refresh CAT: %v", err)
|
||||
cli.expectDisconnect()
|
||||
go cli.dispatchEvent(&events.CATRefreshError{Error: err})
|
||||
}
|
||||
} else if willAutoReconnect {
|
||||
cli.Log.Warnf("Got %d/%s connect failure, assuming automatic reconnect will handle it", int(reason), message)
|
||||
} else {
|
||||
@ -120,7 +148,7 @@ func (cli *Client) handleConnectSuccess(node *waBinary.Node) {
|
||||
cli.Log.Infof("Successfully authenticated")
|
||||
cli.LastSuccessfulConnect = time.Now()
|
||||
cli.AutoReconnectErrors = 0
|
||||
atomic.StoreUint32(&cli.isLoggedIn, 1)
|
||||
cli.isLoggedIn.Store(true)
|
||||
go func() {
|
||||
if dbCount, err := cli.Store.PreKeys.UploadedPreKeyCount(); err != nil {
|
||||
cli.Log.Errorf("Failed to get number of prekeys in database: %v", err)
|
||||
|
90
vendor/go.mau.fi/whatsmeow/download.go
vendored
90
vendor/go.mau.fi/whatsmeow/download.go
vendored
@ -10,6 +10,7 @@ import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@ -17,9 +18,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.mau.fi/util/retryafter"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMediaTransport"
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/socket"
|
||||
"go.mau.fi/whatsmeow/util/cbcutil"
|
||||
@ -208,6 +211,10 @@ func (cli *Client) Download(msg DownloadableMessage) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) DownloadFB(transport *waMediaTransport.WAMediaTransport_Integral, mediaType MediaType) ([]byte, error) {
|
||||
return cli.DownloadMediaWithPath(transport.GetDirectPath(), transport.GetFileEncSHA256(), transport.GetFileSHA256(), transport.GetMediaKey(), -1, mediaType, mediaTypeToMMSType[mediaType])
|
||||
}
|
||||
|
||||
// DownloadMediaWithPath downloads an attachment by manually specifying the path and encryption details.
|
||||
func (cli *Client) DownloadMediaWithPath(directPath string, encFileHash, fileHash, mediaKey []byte, fileLength int, mediaType MediaType, mmsType string) (data []byte, err error) {
|
||||
var mediaConn *MediaConn
|
||||
@ -219,15 +226,16 @@ func (cli *Client) DownloadMediaWithPath(directPath string, encFileHash, fileHas
|
||||
mmsType = mediaTypeToMMSType[mediaType]
|
||||
}
|
||||
for i, host := range mediaConn.Hosts {
|
||||
// TODO omit hash for unencrypted media?
|
||||
mediaURL := fmt.Sprintf("https://%s%s&hash=%s&mms-type=%s&__wa-mms=", host.Hostname, directPath, base64.URLEncoding.EncodeToString(encFileHash), mmsType)
|
||||
data, err = cli.downloadAndDecrypt(mediaURL, mediaKey, mediaType, fileLength, encFileHash, fileHash)
|
||||
// TODO there are probably some errors that shouldn't retry
|
||||
if err != nil {
|
||||
if i >= len(mediaConn.Hosts)-1 {
|
||||
return nil, fmt.Errorf("failed to download media from last host: %w", err)
|
||||
}
|
||||
cli.Log.Warnf("Failed to download media: %s, trying with next host...", err)
|
||||
if err == nil {
|
||||
return
|
||||
} else if i >= len(mediaConn.Hosts)-1 {
|
||||
return nil, fmt.Errorf("failed to download media from last host: %w", err)
|
||||
}
|
||||
// TODO there are probably some errors that shouldn't retry
|
||||
cli.Log.Warnf("Failed to download media: %s, trying with next host...", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -235,8 +243,11 @@ func (cli *Client) DownloadMediaWithPath(directPath string, encFileHash, fileHas
|
||||
func (cli *Client) downloadAndDecrypt(url string, mediaKey []byte, appInfo MediaType, fileLength int, fileEncSha256, fileSha256 []byte) (data []byte, err error) {
|
||||
iv, cipherKey, macKey, _ := getMediaKeys(mediaKey, appInfo)
|
||||
var ciphertext, mac []byte
|
||||
if ciphertext, mac, err = cli.downloadEncryptedMediaWithRetries(url, fileEncSha256); err != nil {
|
||||
if ciphertext, mac, err = cli.downloadPossiblyEncryptedMediaWithRetries(url, fileEncSha256); err != nil {
|
||||
|
||||
} else if mediaKey == nil && fileEncSha256 == nil && mac == nil {
|
||||
// Unencrypted media, just return the downloaded data
|
||||
data = ciphertext
|
||||
} else if err = validateMedia(iv, ciphertext, macKey, mac); err != nil {
|
||||
|
||||
} else if data, err = cbcutil.Decrypt(cipherKey, iv, ciphertext); err != nil {
|
||||
@ -254,52 +265,59 @@ func getMediaKeys(mediaKey []byte, appInfo MediaType) (iv, cipherKey, macKey, re
|
||||
return mediaKeyExpanded[:16], mediaKeyExpanded[16:48], mediaKeyExpanded[48:80], mediaKeyExpanded[80:]
|
||||
}
|
||||
|
||||
func (cli *Client) downloadEncryptedMediaWithRetries(url string, checksum []byte) (file, mac []byte, err error) {
|
||||
func shouldRetryMediaDownload(err error) bool {
|
||||
var netErr net.Error
|
||||
var httpErr DownloadHTTPError
|
||||
return errors.As(err, &netErr) ||
|
||||
strings.HasPrefix(err.Error(), "stream error:") || // hacky check for http2 errors
|
||||
(errors.As(err, &httpErr) && retryafter.Should(httpErr.StatusCode, true))
|
||||
}
|
||||
|
||||
func (cli *Client) downloadPossiblyEncryptedMediaWithRetries(url string, checksum []byte) (file, mac []byte, err error) {
|
||||
for retryNum := 0; retryNum < 5; retryNum++ {
|
||||
file, mac, err = cli.downloadEncryptedMedia(url, checksum)
|
||||
if err == nil {
|
||||
if checksum == nil {
|
||||
file, err = cli.downloadMedia(url)
|
||||
} else {
|
||||
file, mac, err = cli.downloadEncryptedMedia(url, checksum)
|
||||
}
|
||||
if err == nil || !shouldRetryMediaDownload(err) {
|
||||
return
|
||||
}
|
||||
netErr, ok := err.(net.Error)
|
||||
if !ok {
|
||||
// Not a network error, don't retry
|
||||
return
|
||||
retryDuration := time.Duration(retryNum+1) * time.Second
|
||||
var httpErr DownloadHTTPError
|
||||
if errors.As(err, &httpErr) {
|
||||
retryDuration = retryafter.Parse(httpErr.Response.Header.Get("Retry-After"), retryDuration)
|
||||
}
|
||||
cli.Log.Warnf("Failed to download media due to network error: %w, retrying...", netErr)
|
||||
time.Sleep(time.Duration(retryNum+1) * time.Second)
|
||||
cli.Log.Warnf("Failed to download media due to network error: %w, retrying in %s...", err, retryDuration)
|
||||
time.Sleep(retryDuration)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) downloadEncryptedMedia(url string, checksum []byte) (file, mac []byte, err error) {
|
||||
var req *http.Request
|
||||
req, err = http.NewRequest(http.MethodGet, url, nil)
|
||||
func (cli *Client) downloadMedia(url string) ([]byte, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to prepare request: %w", err)
|
||||
return
|
||||
return nil, fmt.Errorf("failed to prepare request: %w", err)
|
||||
}
|
||||
req.Header.Set("Origin", socket.Origin)
|
||||
req.Header.Set("Referer", socket.Origin+"/")
|
||||
var resp *http.Response
|
||||
resp, err = cli.http.Do(req)
|
||||
if cli.MessengerConfig != nil {
|
||||
req.Header.Set("User-Agent", cli.MessengerConfig.UserAgent)
|
||||
}
|
||||
// TODO user agent for whatsapp downloads?
|
||||
resp, err := cli.http.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if resp.StatusCode == http.StatusForbidden {
|
||||
err = ErrMediaDownloadFailedWith403
|
||||
} else if resp.StatusCode == http.StatusNotFound {
|
||||
err = ErrMediaDownloadFailedWith404
|
||||
} else if resp.StatusCode == http.StatusGone {
|
||||
err = ErrMediaDownloadFailedWith410
|
||||
} else {
|
||||
err = fmt.Errorf("download failed with status code %d", resp.StatusCode)
|
||||
}
|
||||
return
|
||||
return nil, DownloadHTTPError{Response: resp}
|
||||
}
|
||||
var data []byte
|
||||
data, err = io.ReadAll(resp.Body)
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func (cli *Client) downloadEncryptedMedia(url string, checksum []byte) (file, mac []byte, err error) {
|
||||
data, err := cli.downloadMedia(url)
|
||||
if err != nil {
|
||||
return
|
||||
} else if len(data) <= 10 {
|
||||
|
22
vendor/go.mau.fi/whatsmeow/errors.go
vendored
22
vendor/go.mau.fi/whatsmeow/errors.go
vendored
@ -9,6 +9,7 @@ package whatsmeow
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
)
|
||||
@ -103,15 +104,28 @@ var (
|
||||
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 normal (non-AD) JID")
|
||||
ErrRecipientADJID = errors.New("message recipient must be a user JID with no device part")
|
||||
ErrServerReturnedError = errors.New("server returned error")
|
||||
)
|
||||
|
||||
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 = errors.New("download failed with status code 403")
|
||||
ErrMediaDownloadFailedWith404 = errors.New("download failed with status code 404")
|
||||
ErrMediaDownloadFailedWith410 = errors.New("download failed with status code 410")
|
||||
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")
|
||||
|
21
vendor/go.mau.fi/whatsmeow/go.mod
vendored
Normal file
21
vendor/go.mau.fi/whatsmeow/go.mod
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
module go.mau.fi/whatsmeow
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/rs/zerolog v1.32.0
|
||||
go.mau.fi/libsignal v0.1.0
|
||||
go.mau.fi/util v0.4.1
|
||||
golang.org/x/crypto v0.23.0
|
||||
golang.org/x/net v0.25.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
)
|
44
vendor/go.mau.fi/whatsmeow/go.sum
vendored
Normal file
44
vendor/go.mau.fi/whatsmeow/go.sum
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
|
||||
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
|
||||
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c=
|
||||
go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I=
|
||||
go.mau.fi/util v0.4.1 h1:3EC9KxIXo5+h869zDGf5OOZklRd/FjeVnimTwtm3owg=
|
||||
go.mau.fi/util v0.4.1/go.mod h1:GjkTEBsehYZbSh2LlE6cWEn+6ZIZTGrTMM/5DMNlmFY=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
144
vendor/go.mau.fi/whatsmeow/group.go
vendored
144
vendor/go.mau.fi/whatsmeow/group.go
vendored
@ -148,30 +148,93 @@ const (
|
||||
)
|
||||
|
||||
// UpdateGroupParticipants can be used to add, remove, promote and demote members in a WhatsApp group.
|
||||
func (cli *Client) UpdateGroupParticipants(jid types.JID, participantChanges map[types.JID]ParticipantChange) (*waBinary.Node, error) {
|
||||
func (cli *Client) UpdateGroupParticipants(jid types.JID, participantChanges []types.JID, action ParticipantChange) ([]types.GroupParticipant, error) {
|
||||
content := make([]waBinary.Node, len(participantChanges))
|
||||
i := 0
|
||||
for participantJID, change := range participantChanges {
|
||||
for i, participantJID := range participantChanges {
|
||||
content[i] = waBinary.Node{
|
||||
Tag: string(change),
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "participant",
|
||||
Attrs: waBinary.Attrs{"jid": participantJID},
|
||||
}},
|
||||
Tag: "participant",
|
||||
Attrs: waBinary.Attrs{"jid": participantJID},
|
||||
}
|
||||
i++
|
||||
}
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Namespace: "w:g2",
|
||||
Type: iqSet,
|
||||
To: jid,
|
||||
Content: content,
|
||||
resp, err := cli.sendGroupIQ(context.TODO(), iqSet, jid, waBinary.Node{
|
||||
Tag: string(action),
|
||||
Content: content,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO proper return value?
|
||||
return resp, nil
|
||||
requestAction, ok := resp.GetOptionalChildByTag(string(action))
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: string(action), In: "response to group participants update"}
|
||||
}
|
||||
requestParticipants := requestAction.GetChildrenByTag("participant")
|
||||
participants := make([]types.GroupParticipant, len(requestParticipants))
|
||||
for i, child := range requestParticipants {
|
||||
participants[i] = parseParticipant(child.AttrGetter(), &child)
|
||||
}
|
||||
return participants, nil
|
||||
}
|
||||
|
||||
// GetGroupRequestParticipants gets the list of participants that have requested to join the group.
|
||||
func (cli *Client) GetGroupRequestParticipants(jid types.JID) ([]types.JID, error) {
|
||||
resp, err := cli.sendGroupIQ(context.TODO(), iqGet, jid, waBinary.Node{
|
||||
Tag: "membership_approval_requests",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request, ok := resp.GetOptionalChildByTag("membership_approval_requests")
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: "membership_approval_requests", In: "response to group request participants query"}
|
||||
}
|
||||
requestParticipants := request.GetChildrenByTag("membership_approval_request")
|
||||
participants := make([]types.JID, len(requestParticipants))
|
||||
for i, req := range requestParticipants {
|
||||
participants[i] = req.AttrGetter().JID("jid")
|
||||
}
|
||||
return participants, nil
|
||||
}
|
||||
|
||||
type ParticipantRequestChange string
|
||||
|
||||
const (
|
||||
ParticipantChangeApprove ParticipantRequestChange = "approve"
|
||||
ParticipantChangeReject ParticipantRequestChange = "reject"
|
||||
)
|
||||
|
||||
// UpdateGroupRequestParticipants can be used to approve or reject requests to join the group.
|
||||
func (cli *Client) UpdateGroupRequestParticipants(jid types.JID, participantChanges []types.JID, action ParticipantRequestChange) ([]types.GroupParticipant, error) {
|
||||
content := make([]waBinary.Node, len(participantChanges))
|
||||
for i, participantJID := range participantChanges {
|
||||
content[i] = waBinary.Node{
|
||||
Tag: "participant",
|
||||
Attrs: waBinary.Attrs{"jid": participantJID},
|
||||
}
|
||||
}
|
||||
resp, err := cli.sendGroupIQ(context.TODO(), iqSet, jid, waBinary.Node{
|
||||
Tag: "membership_requests_action",
|
||||
Content: []waBinary.Node{{
|
||||
Tag: string(action),
|
||||
Content: content,
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request, ok := resp.GetOptionalChildByTag("membership_requests_action")
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: "membership_requests_action", In: "response to group request participants update"}
|
||||
}
|
||||
requestAction, ok := request.GetOptionalChildByTag(string(action))
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: string(action), In: "response to group request participants update"}
|
||||
}
|
||||
requestParticipants := requestAction.GetChildrenByTag("participant")
|
||||
participants := make([]types.GroupParticipant, len(requestParticipants))
|
||||
for i, child := range requestParticipants {
|
||||
participants[i] = parseParticipant(child.AttrGetter(), &child)
|
||||
}
|
||||
return participants, nil
|
||||
}
|
||||
|
||||
// SetGroupPhoto updates the group picture/icon of the given group on WhatsApp.
|
||||
@ -501,6 +564,33 @@ func (cli *Client) getGroupMembers(ctx context.Context, jid types.JID) ([]types.
|
||||
return cli.groupParticipantsCache[jid], nil
|
||||
}
|
||||
|
||||
func parseParticipant(childAG *waBinary.AttrUtility, child *waBinary.Node) types.GroupParticipant {
|
||||
pcpType := childAG.OptionalString("type")
|
||||
participant := types.GroupParticipant{
|
||||
IsAdmin: pcpType == "admin" || pcpType == "superadmin",
|
||||
IsSuperAdmin: pcpType == "superadmin",
|
||||
JID: childAG.JID("jid"),
|
||||
LID: childAG.OptionalJIDOrEmpty("lid"),
|
||||
DisplayName: childAG.OptionalString("display_name"),
|
||||
}
|
||||
if participant.JID.Server == types.HiddenUserServer && participant.LID.IsEmpty() {
|
||||
participant.LID = participant.JID
|
||||
//participant.JID = types.EmptyJID
|
||||
}
|
||||
if errorCode := childAG.OptionalInt("error"); errorCode != 0 {
|
||||
participant.Error = errorCode
|
||||
addRequest, ok := child.GetOptionalChildByTag("add_request")
|
||||
if ok {
|
||||
addAG := addRequest.AttrGetter()
|
||||
participant.AddRequest = &types.GroupParticipantAddRequest{
|
||||
Code: addAG.String("code"),
|
||||
Expiration: addAG.UnixTime("expiration"),
|
||||
}
|
||||
}
|
||||
}
|
||||
return participant
|
||||
}
|
||||
|
||||
func (cli *Client) parseGroupNode(groupNode *waBinary.Node) (*types.GroupInfo, error) {
|
||||
var group types.GroupInfo
|
||||
ag := groupNode.AttrGetter()
|
||||
@ -521,24 +611,7 @@ func (cli *Client) parseGroupNode(groupNode *waBinary.Node) (*types.GroupInfo, e
|
||||
childAG := child.AttrGetter()
|
||||
switch child.Tag {
|
||||
case "participant":
|
||||
pcpType := childAG.OptionalString("type")
|
||||
participant := types.GroupParticipant{
|
||||
IsAdmin: pcpType == "admin" || pcpType == "superadmin",
|
||||
IsSuperAdmin: pcpType == "superadmin",
|
||||
JID: childAG.JID("jid"),
|
||||
}
|
||||
if errorCode := childAG.OptionalInt("error"); errorCode != 0 {
|
||||
participant.Error = errorCode
|
||||
addRequest, ok := child.GetOptionalChildByTag("add_request")
|
||||
if ok {
|
||||
addAG := addRequest.AttrGetter()
|
||||
participant.AddRequest = &types.GroupParticipantAddRequest{
|
||||
Code: addAG.String("code"),
|
||||
Expiration: addAG.UnixTime("expiration"),
|
||||
}
|
||||
}
|
||||
}
|
||||
group.Participants = append(group.Participants, participant)
|
||||
group.Participants = append(group.Participants, parseParticipant(childAG, &child))
|
||||
case "description":
|
||||
body, bodyOK := child.GetOptionalChildByTag("body")
|
||||
if bodyOK {
|
||||
@ -565,6 +638,9 @@ func (cli *Client) parseGroupNode(groupNode *waBinary.Node) (*types.GroupInfo, e
|
||||
case "parent":
|
||||
group.IsParent = true
|
||||
group.DefaultMembershipApprovalMode = childAG.OptionalString("default_membership_approval_mode")
|
||||
case "incognito":
|
||||
group.IsIncognito = true
|
||||
// TODO: membership_approval_mode
|
||||
default:
|
||||
cli.Log.Debugf("Unknown element in group node %s: %s", group.JID.String(), child.XMLString())
|
||||
}
|
||||
|
69
vendor/go.mau.fi/whatsmeow/handshake.go
vendored
69
vendor/go.mau.fi/whatsmeow/handshake.go
vendored
@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.mau.fi/libsignal/ecc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
@ -19,6 +20,9 @@ import (
|
||||
)
|
||||
|
||||
const NoiseHandshakeResponseTimeout = 20 * time.Second
|
||||
const WACertIssuerSerial = 0
|
||||
|
||||
var WACertPubKey = [...]byte{0x14, 0x23, 0x75, 0x57, 0x4d, 0xa, 0x58, 0x71, 0x66, 0xaa, 0xe7, 0x1e, 0xbe, 0x51, 0x64, 0x37, 0xc4, 0xa2, 0x8b, 0x73, 0xe3, 0x69, 0x5c, 0x6c, 0xe1, 0xf7, 0xf9, 0x54, 0x5d, 0xa8, 0xee, 0x6b}
|
||||
|
||||
// doHandshake implements the Noise_XX_25519_AESGCM_SHA256 handshake for the WhatsApp web API.
|
||||
func (cli *Client) doHandshake(fs *socket.FrameSocket, ephemeralKP keys.KeyPair) error {
|
||||
@ -76,23 +80,8 @@ func (cli *Client) doHandshake(fs *socket.FrameSocket, ephemeralKP keys.KeyPair)
|
||||
certDecrypted, err := nh.Decrypt(certificateCiphertext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt noise certificate ciphertext: %w", err)
|
||||
}
|
||||
var cert waProto.NoiseCertificate
|
||||
err = proto.Unmarshal(certDecrypted, &cert)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal noise certificate: %w", err)
|
||||
}
|
||||
certDetailsRaw := cert.GetDetails()
|
||||
certSignature := cert.GetSignature()
|
||||
if certDetailsRaw == nil || certSignature == nil {
|
||||
return fmt.Errorf("missing parts of noise certificate")
|
||||
}
|
||||
var certDetails waProto.NoiseCertificate_Details
|
||||
err = proto.Unmarshal(certDetailsRaw, &certDetails)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal noise certificate details: %w", err)
|
||||
} else if !bytes.Equal(certDetails.GetKey(), staticDecrypted) {
|
||||
return fmt.Errorf("cert key doesn't match decrypted static")
|
||||
} else if err = verifyServerCert(certDecrypted, staticDecrypted); err != nil {
|
||||
return fmt.Errorf("failed to verify server cert: %w", err)
|
||||
}
|
||||
|
||||
encryptedPubkey := nh.Encrypt(cli.Store.NoiseKey.Pub[:])
|
||||
@ -101,7 +90,14 @@ func (cli *Client) doHandshake(fs *socket.FrameSocket, ephemeralKP keys.KeyPair)
|
||||
return fmt.Errorf("failed to mix noise private key in: %w", err)
|
||||
}
|
||||
|
||||
clientFinishPayloadBytes, err := proto.Marshal(cli.Store.GetClientPayload())
|
||||
var clientPayload *waProto.ClientPayload
|
||||
if cli.GetClientPayload != nil {
|
||||
clientPayload = cli.GetClientPayload()
|
||||
} else {
|
||||
clientPayload = cli.Store.GetClientPayload()
|
||||
}
|
||||
|
||||
clientFinishPayloadBytes, err := proto.Marshal(clientPayload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal client finish payload: %w", err)
|
||||
}
|
||||
@ -129,3 +125,40 @@ func (cli *Client) doHandshake(fs *socket.FrameSocket, ephemeralKP keys.KeyPair)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyServerCert(certDecrypted, staticDecrypted []byte) error {
|
||||
var certChain waProto.CertChain
|
||||
err := proto.Unmarshal(certDecrypted, &certChain)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal noise certificate: %w", err)
|
||||
}
|
||||
var intermediateCertDetails, leafCertDetails waProto.CertChain_NoiseCertificate_Details
|
||||
intermediateCertDetailsRaw := certChain.GetIntermediate().GetDetails()
|
||||
intermediateCertSignature := certChain.GetIntermediate().GetSignature()
|
||||
leafCertDetailsRaw := certChain.GetLeaf().GetDetails()
|
||||
leafCertSignature := certChain.GetLeaf().GetSignature()
|
||||
if intermediateCertDetailsRaw == nil || intermediateCertSignature == nil || leafCertDetailsRaw == nil || leafCertSignature == nil {
|
||||
return fmt.Errorf("missing parts of noise certificate")
|
||||
} else if len(intermediateCertSignature) != 64 {
|
||||
return fmt.Errorf("unexpected length of intermediate cert signature %d (expected 64)", len(intermediateCertSignature))
|
||||
} else if len(leafCertSignature) != 64 {
|
||||
return fmt.Errorf("unexpected length of leaf cert signature %d (expected 64)", len(leafCertSignature))
|
||||
} else if !ecc.VerifySignature(ecc.NewDjbECPublicKey(WACertPubKey), intermediateCertDetailsRaw, [64]byte(intermediateCertSignature)) {
|
||||
return fmt.Errorf("failed to verify intermediate cert signature")
|
||||
} else if err = proto.Unmarshal(intermediateCertDetailsRaw, &intermediateCertDetails); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal noise certificate details: %w", err)
|
||||
} else if intermediateCertDetails.GetIssuerSerial() != WACertIssuerSerial {
|
||||
return fmt.Errorf("unexpected intermediate issuer serial %d (expected %d)", intermediateCertDetails.GetIssuerSerial(), WACertIssuerSerial)
|
||||
} else if len(intermediateCertDetails.GetKey()) != 32 {
|
||||
return fmt.Errorf("unexpected length of intermediate cert key %d (expected 32)", len(intermediateCertDetails.GetKey()))
|
||||
} else if !ecc.VerifySignature(ecc.NewDjbECPublicKey([32]byte(intermediateCertDetails.GetKey())), leafCertDetailsRaw, [64]byte(leafCertSignature)) {
|
||||
return fmt.Errorf("failed to verify intermediate cert signature")
|
||||
} else if err = proto.Unmarshal(leafCertDetailsRaw, &leafCertDetails); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal noise certificate details: %w", err)
|
||||
} else if leafCertDetails.GetIssuerSerial() != intermediateCertDetails.GetSerial() {
|
||||
return fmt.Errorf("unexpected leaf issuer serial %d (expected %d)", leafCertDetails.GetIssuerSerial(), intermediateCertDetails.GetSerial())
|
||||
} else if !bytes.Equal(leafCertDetails.GetKey(), staticDecrypted) {
|
||||
return fmt.Errorf("cert key doesn't match decrypted static")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
18
vendor/go.mau.fi/whatsmeow/internals.go
vendored
18
vendor/go.mau.fi/whatsmeow/internals.go
vendored
@ -9,6 +9,8 @@ package whatsmeow
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.mau.fi/libsignal/keys/prekey"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
)
|
||||
@ -66,3 +68,19 @@ func (int *DangerousInternalClient) RequestAppStateKeys(ctx context.Context, key
|
||||
func (int *DangerousInternalClient) SendRetryReceipt(node *waBinary.Node, info *types.MessageInfo, forceIncludeIdentity bool) {
|
||||
int.c.sendRetryReceipt(node, info, forceIncludeIdentity)
|
||||
}
|
||||
|
||||
func (int *DangerousInternalClient) EncryptMessageForDevice(plaintext []byte, to types.JID, bundle *prekey.Bundle, extraAttrs waBinary.Attrs) (*waBinary.Node, bool, error) {
|
||||
return int.c.encryptMessageForDevice(plaintext, to, bundle, extraAttrs)
|
||||
}
|
||||
|
||||
func (int *DangerousInternalClient) GetOwnID() types.JID {
|
||||
return int.c.getOwnID()
|
||||
}
|
||||
|
||||
func (int *DangerousInternalClient) DecryptDM(child *waBinary.Node, from types.JID, isPreKey bool) ([]byte, error) {
|
||||
return int.c.decryptDM(child, from, isPreKey)
|
||||
}
|
||||
|
||||
func (int *DangerousInternalClient) MakeDeviceIdentityNode() waBinary.Node {
|
||||
return int.c.makeDeviceIdentityNode()
|
||||
}
|
||||
|
2
vendor/go.mau.fi/whatsmeow/keepalive.go
vendored
2
vendor/go.mau.fi/whatsmeow/keepalive.go
vendored
@ -11,7 +11,6 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
)
|
||||
@ -67,7 +66,6 @@ func (cli *Client) sendKeepAlive(ctx context.Context) (isSuccess, shouldContinue
|
||||
Namespace: "w:p",
|
||||
Type: "get",
|
||||
To: types.ServerJID,
|
||||
Content: []waBinary.Node{{Tag: "ping"}},
|
||||
})
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Failed to send keepalive: %v", err)
|
||||
|
11
vendor/go.mau.fi/whatsmeow/mdtest/README.md
vendored
Normal file
11
vendor/go.mau.fi/whatsmeow/mdtest/README.md
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# mdtest
|
||||
|
||||
This is a simple tool for testing whatsmeow.
|
||||
|
||||
1. Clone the repository.
|
||||
2. Run `go build` inside this directory.
|
||||
3. Run `./mdtest` to start the program. Optionally, use `rlwrap ./mdtest` to get a nicer prompt.
|
||||
Add `-debug` if you want to see the raw data being sent/received.
|
||||
4. On the first run, scan the QR code. On future runs, the program will remember you (unless `mdtest.db` is deleted).
|
||||
|
||||
New messages will be automatically logged. To send a message, use `send <jid> <message>`
|
29
vendor/go.mau.fi/whatsmeow/mdtest/go.mod
vendored
Normal file
29
vendor/go.mau.fi/whatsmeow/mdtest/go.mod
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
module go.mau.fi/whatsmeow/mdtest
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.22.0
|
||||
|
||||
require (
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
github.com/mdp/qrterminal/v3 v3.0.0
|
||||
go.mau.fi/whatsmeow v0.0.0-20230805111647-405414b9b5c0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.0.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/rs/zerolog v1.32.0 // indirect
|
||||
go.mau.fi/libsignal v0.1.0 // indirect
|
||||
go.mau.fi/util v0.4.1 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
rsc.io/qr v0.2.0 // indirect
|
||||
)
|
||||
|
||||
replace go.mau.fi/whatsmeow => ../
|
54
vendor/go.mau.fi/whatsmeow/mdtest/go.sum
vendored
Normal file
54
vendor/go.mau.fi/whatsmeow/mdtest/go.sum
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
|
||||
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mdp/qrterminal v1.0.1/go.mod h1:Z33WhxQe9B6CdW37HaVqcRKzP+kByF3q/qLxOGe12xQ=
|
||||
github.com/mdp/qrterminal/v3 v3.0.0 h1:ywQqLRBXWTktytQNDKFjhAvoGkLVN3J2tAFZ0kMd9xQ=
|
||||
github.com/mdp/qrterminal/v3 v3.0.0/go.mod h1:NJpfAs7OAm77Dy8EkWrtE4aq+cE6McoLXlBqXQEwvE0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
|
||||
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c=
|
||||
go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I=
|
||||
go.mau.fi/util v0.4.1 h1:3EC9KxIXo5+h869zDGf5OOZklRd/FjeVnimTwtm3owg=
|
||||
go.mau.fi/util v0.4.1/go.mod h1:GjkTEBsehYZbSh2LlE6cWEn+6ZIZTGrTMM/5DMNlmFY=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
|
||||
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
|
1165
vendor/go.mau.fi/whatsmeow/mdtest/main.go
vendored
Normal file
1165
vendor/go.mau.fi/whatsmeow/mdtest/main.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
vendor/go.mau.fi/whatsmeow/mediaretry.go
vendored
4
vendor/go.mau.fi/whatsmeow/mediaretry.go
vendored
@ -9,6 +9,7 @@ package whatsmeow
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.mau.fi/util/random"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
@ -17,7 +18,6 @@ import (
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
"go.mau.fi/whatsmeow/util/gcmutil"
|
||||
"go.mau.fi/whatsmeow/util/hkdfutil"
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
func getMediaRetryKey(mediaKey []byte) (cipherKey []byte) {
|
||||
@ -34,7 +34,7 @@ func encryptMediaRetryReceipt(messageID types.MessageID, mediaKey []byte) (ciphe
|
||||
err = fmt.Errorf("failed to marshal payload: %w", err)
|
||||
return
|
||||
}
|
||||
iv = randbytes.Make(12)
|
||||
iv = random.Bytes(12)
|
||||
ciphertext, err = gcmutil.Encrypt(getMediaRetryKey(mediaKey), iv, plaintext, []byte(messageID))
|
||||
return
|
||||
}
|
||||
|
139
vendor/go.mau.fi/whatsmeow/message.go
vendored
139
vendor/go.mau.fi/whatsmeow/message.go
vendored
@ -14,15 +14,14 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime/debug"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.mau.fi/libsignal/signalerror"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.mau.fi/libsignal/groups"
|
||||
"go.mau.fi/libsignal/protocol"
|
||||
"go.mau.fi/libsignal/session"
|
||||
"go.mau.fi/libsignal/signalerror"
|
||||
"go.mau.fi/util/random"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.mau.fi/whatsmeow/appstate"
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
@ -30,7 +29,6 @@ import (
|
||||
"go.mau.fi/whatsmeow/store"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
var pbSerializer = store.SignalProtobufSerializer
|
||||
@ -46,7 +44,12 @@ func (cli *Client) handleEncryptedMessage(node *waBinary.Node) {
|
||||
if len(info.PushName) > 0 && info.PushName != "-" {
|
||||
go cli.updatePushName(info.Sender, info, info.PushName)
|
||||
}
|
||||
cli.decryptMessages(info, node)
|
||||
go cli.sendAck(node)
|
||||
if info.Sender.Server == types.NewsletterServer {
|
||||
cli.handlePlaintextMessage(info, node)
|
||||
} else {
|
||||
cli.decryptMessages(info, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +75,10 @@ func (cli *Client) parseMessageSource(node *waBinary.Node, requireParticipant bo
|
||||
if from.Server == types.BroadcastServer {
|
||||
source.BroadcastListOwner = ag.OptionalJIDOrEmpty("recipient")
|
||||
}
|
||||
} else if from.Server == types.NewsletterServer {
|
||||
source.Chat = from
|
||||
source.Sender = from
|
||||
// TODO IsFromMe?
|
||||
} else if from.User == clientID.User {
|
||||
source.IsFromMe = true
|
||||
source.Sender = from
|
||||
@ -98,40 +105,83 @@ func (cli *Client) parseMessageInfo(node *waBinary.Node) (*types.MessageInfo, er
|
||||
}
|
||||
ag := node.AttrGetter()
|
||||
info.ID = types.MessageID(ag.String("id"))
|
||||
info.ServerID = types.MessageServerID(ag.OptionalInt("server_id"))
|
||||
info.Timestamp = ag.UnixTime("t")
|
||||
info.PushName = ag.OptionalString("notify")
|
||||
info.Category = ag.OptionalString("category")
|
||||
info.Type = ag.OptionalString("type")
|
||||
info.Edit = types.EditAttribute(ag.OptionalString("edit"))
|
||||
if !ag.OK() {
|
||||
return nil, ag.Error()
|
||||
}
|
||||
|
||||
for _, child := range node.GetChildren() {
|
||||
if child.Tag == "multicast" {
|
||||
switch child.Tag {
|
||||
case "multicast":
|
||||
info.Multicast = true
|
||||
} else if child.Tag == "verified_name" {
|
||||
case "verified_name":
|
||||
info.VerifiedName, err = parseVerifiedNameContent(child)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Failed to parse verified_name node in %s: %v", info.ID, err)
|
||||
}
|
||||
} else if mediaType, ok := child.AttrGetter().GetString("mediatype", false); ok {
|
||||
info.MediaType = mediaType
|
||||
case "franking":
|
||||
// TODO
|
||||
case "trace":
|
||||
// TODO
|
||||
default:
|
||||
if mediaType, ok := child.AttrGetter().GetString("mediatype", false); ok {
|
||||
info.MediaType = mediaType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (cli *Client) handlePlaintextMessage(info *types.MessageInfo, node *waBinary.Node) {
|
||||
// TODO edits have an additional <meta msg_edit_t="1696321271735" original_msg_t="1696321248"/> node
|
||||
plaintext, ok := node.GetOptionalChildByTag("plaintext")
|
||||
if !ok {
|
||||
// 3:
|
||||
return
|
||||
}
|
||||
plaintextBody, ok := plaintext.Content.([]byte)
|
||||
if !ok {
|
||||
cli.Log.Warnf("Plaintext message from %s doesn't have byte content", info.SourceString())
|
||||
return
|
||||
}
|
||||
var msg waProto.Message
|
||||
err := proto.Unmarshal(plaintextBody, &msg)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Error unmarshaling plaintext message from %s: %v", info.SourceString(), err)
|
||||
return
|
||||
}
|
||||
cli.storeMessageSecret(info, &msg)
|
||||
evt := &events.Message{
|
||||
Info: *info,
|
||||
RawMessage: &msg,
|
||||
}
|
||||
meta, ok := node.GetOptionalChildByTag("meta")
|
||||
if ok {
|
||||
evt.NewsletterMeta = &events.NewsletterMessageMeta{
|
||||
EditTS: meta.AttrGetter().UnixMilli("msg_edit_t"),
|
||||
OriginalTS: meta.AttrGetter().UnixTime("original_msg_t"),
|
||||
}
|
||||
}
|
||||
cli.dispatchEvent(evt.UnwrapRaw())
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) decryptMessages(info *types.MessageInfo, node *waBinary.Node) {
|
||||
go cli.sendAck(node)
|
||||
if len(node.GetChildrenByTag("unavailable")) > 0 && len(node.GetChildrenByTag("enc")) == 0 {
|
||||
cli.Log.Warnf("Unavailable message %s from %s", info.ID, info.SourceString())
|
||||
go cli.sendRetryReceipt(node, info, true)
|
||||
cli.dispatchEvent(&events.UndecryptableMessage{Info: *info, IsUnavailable: true})
|
||||
return
|
||||
}
|
||||
|
||||
children := node.GetChildren()
|
||||
cli.Log.Debugf("Decrypting %d messages from %s", len(children), info.SourceString())
|
||||
cli.Log.Debugf("Decrypting message from %s", info.SourceString())
|
||||
handled := false
|
||||
containsDirectMsg := false
|
||||
for _, child := range children {
|
||||
@ -158,28 +208,33 @@ func (cli *Client) decryptMessages(info *types.MessageInfo, node *waBinary.Node)
|
||||
cli.Log.Warnf("Error decrypting message from %s: %v", info.SourceString(), err)
|
||||
isUnavailable := encType == "skmsg" && !containsDirectMsg && errors.Is(err, signalerror.ErrNoSenderKeyForUser)
|
||||
go cli.sendRetryReceipt(node, info, isUnavailable)
|
||||
decryptFailMode, _ := child.Attrs["decrypt-fail"].(string)
|
||||
cli.dispatchEvent(&events.UndecryptableMessage{
|
||||
Info: *info,
|
||||
IsUnavailable: isUnavailable,
|
||||
DecryptFailMode: events.DecryptFailMode(decryptFailMode),
|
||||
DecryptFailMode: events.DecryptFailMode(ag.OptionalString("decrypt-fail")),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var msg waProto.Message
|
||||
err = proto.Unmarshal(decrypted, &msg)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Error unmarshaling decrypted message from %s: %v", info.SourceString(), err)
|
||||
continue
|
||||
}
|
||||
retryCount := ag.OptionalInt("count")
|
||||
if retryCount > 0 {
|
||||
cli.cancelDelayedRequestFromPhone(info.ID)
|
||||
}
|
||||
|
||||
cli.handleDecryptedMessage(info, &msg, retryCount)
|
||||
handled = true
|
||||
var msg waProto.Message
|
||||
switch ag.Int("v") {
|
||||
case 2:
|
||||
err = proto.Unmarshal(decrypted, &msg)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Error unmarshaling decrypted message from %s: %v", info.SourceString(), err)
|
||||
continue
|
||||
}
|
||||
cli.handleDecryptedMessage(info, &msg, retryCount)
|
||||
handled = true
|
||||
case 3:
|
||||
handled = cli.handleDecryptedArmadillo(info, decrypted, retryCount)
|
||||
default:
|
||||
cli.Log.Warnf("Unknown version %d in decrypted message from %s", ag.Int("v"), info.SourceString())
|
||||
}
|
||||
}
|
||||
if handled {
|
||||
go cli.sendMessageReceipt(info)
|
||||
@ -228,6 +283,9 @@ func (cli *Client) decryptDM(child *waBinary.Node, from types.JID, isPreKey bool
|
||||
return nil, fmt.Errorf("failed to decrypt normal message: %w", err)
|
||||
}
|
||||
}
|
||||
if child.AttrGetter().Int("v") == 3 {
|
||||
return plaintext, nil
|
||||
}
|
||||
return unpadMessage(plaintext)
|
||||
}
|
||||
|
||||
@ -245,6 +303,9 @@ func (cli *Client) decryptGroupMsg(child *waBinary.Node, from types.JID, chat ty
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt group message: %w", err)
|
||||
}
|
||||
if child.AttrGetter().Int("v") == 3 {
|
||||
return plaintext, nil
|
||||
}
|
||||
return unpadMessage(plaintext)
|
||||
}
|
||||
|
||||
@ -267,19 +328,19 @@ func unpadMessage(plaintext []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
func padMessage(plaintext []byte) []byte {
|
||||
pad := randbytes.Make(1)
|
||||
pad := random.Bytes(1)
|
||||
pad[0] &= 0xf
|
||||
if pad[0] == 0 {
|
||||
pad[0] = 0xf
|
||||
}
|
||||
plaintext = append(plaintext, bytes.Repeat(pad[:], int(pad[0]))...)
|
||||
plaintext = append(plaintext, bytes.Repeat(pad, int(pad[0]))...)
|
||||
return plaintext
|
||||
}
|
||||
|
||||
func (cli *Client) handleSenderKeyDistributionMessage(chat, from types.JID, rawSKDMsg *waProto.SenderKeyDistributionMessage) {
|
||||
func (cli *Client) handleSenderKeyDistributionMessage(chat, from types.JID, axolotlSKDM []byte) {
|
||||
builder := groups.NewGroupSessionBuilder(cli.Store, pbSerializer)
|
||||
senderKeyName := protocol.NewSenderKeyName(chat.String(), from.SignalAddress())
|
||||
sdkMsg, err := protocol.NewSenderKeyDistributionMessageFromBytes(rawSKDMsg.AxolotlSenderKeyDistributionMessage, pbSerializer.SenderKeyDistributionMessage)
|
||||
sdkMsg, err := protocol.NewSenderKeyDistributionMessageFromBytes(axolotlSKDM, pbSerializer.SenderKeyDistributionMessage)
|
||||
if err != nil {
|
||||
cli.Log.Errorf("Failed to parse sender key distribution message from %s for %s: %v", from, chat, err)
|
||||
return
|
||||
@ -290,7 +351,7 @@ func (cli *Client) handleSenderKeyDistributionMessage(chat, from types.JID, rawS
|
||||
|
||||
func (cli *Client) handleHistorySyncNotificationLoop() {
|
||||
defer func() {
|
||||
atomic.StoreUint32(&cli.historySyncHandlerStarted, 0)
|
||||
cli.historySyncHandlerStarted.Store(false)
|
||||
err := recover()
|
||||
if err != nil {
|
||||
cli.Log.Errorf("History sync handler panicked: %v\n%s", err, debug.Stack())
|
||||
@ -298,7 +359,7 @@ func (cli *Client) handleHistorySyncNotificationLoop() {
|
||||
|
||||
// Check in case something new appeared in the channel between the loop stopping
|
||||
// and the atomic variable being updated. If yes, restart the loop.
|
||||
if len(cli.historySyncNotifications) > 0 && atomic.CompareAndSwapUint32(&cli.historySyncHandlerStarted, 0, 1) {
|
||||
if len(cli.historySyncNotifications) > 0 && cli.historySyncHandlerStarted.CompareAndSwap(false, true) {
|
||||
cli.Log.Warnf("New history sync notifications appeared after loop stopped, restarting loop...")
|
||||
go cli.handleHistorySyncNotificationLoop()
|
||||
}
|
||||
@ -391,10 +452,10 @@ func (cli *Client) handleProtocolMessage(info *types.MessageInfo, msg *waProto.M
|
||||
|
||||
if protoMsg.GetHistorySyncNotification() != nil && info.IsFromMe {
|
||||
cli.historySyncNotifications <- protoMsg.HistorySyncNotification
|
||||
if atomic.CompareAndSwapUint32(&cli.historySyncHandlerStarted, 0, 1) {
|
||||
if cli.historySyncHandlerStarted.CompareAndSwap(false, true) {
|
||||
go cli.handleHistorySyncNotificationLoop()
|
||||
}
|
||||
go cli.sendProtocolMessageReceipt(info.ID, "hist_sync")
|
||||
go cli.sendProtocolMessageReceipt(info.ID, types.ReceiptTypeHistorySync)
|
||||
}
|
||||
|
||||
if protoMsg.GetPeerDataOperationRequestResponseMessage().GetPeerDataOperationRequestType() == waProto.PeerDataOperationRequestType_PLACEHOLDER_MESSAGE_RESEND {
|
||||
@ -406,7 +467,7 @@ func (cli *Client) handleProtocolMessage(info *types.MessageInfo, msg *waProto.M
|
||||
}
|
||||
|
||||
if info.Category == "peer" {
|
||||
go cli.sendProtocolMessageReceipt(info.ID, "peer_msg")
|
||||
go cli.sendProtocolMessageReceipt(info.ID, types.ReceiptTypePeerMsg)
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,9 +478,9 @@ func (cli *Client) processProtocolParts(info *types.MessageInfo, msg *waProto.Me
|
||||
}
|
||||
if msg.GetSenderKeyDistributionMessage() != nil {
|
||||
if !info.IsGroup {
|
||||
cli.Log.Warnf("Got sender key distribution message in non-group chat from", info.Sender)
|
||||
cli.Log.Warnf("Got sender key distribution message in non-group chat from %s", info.Sender)
|
||||
} else {
|
||||
cli.handleSenderKeyDistributionMessage(info.Chat, info.Sender, msg.SenderKeyDistributionMessage)
|
||||
cli.handleSenderKeyDistributionMessage(info.Chat, info.Sender, msg.SenderKeyDistributionMessage.AxolotlSenderKeyDistributionMessage)
|
||||
}
|
||||
}
|
||||
// N.B. Edits are protocol messages, but they're also wrapped inside EditedMessage,
|
||||
@ -427,6 +488,10 @@ func (cli *Client) processProtocolParts(info *types.MessageInfo, msg *waProto.Me
|
||||
if msg.GetProtocolMessage() != nil {
|
||||
cli.handleProtocolMessage(info, msg)
|
||||
}
|
||||
cli.storeMessageSecret(info, msg)
|
||||
}
|
||||
|
||||
func (cli *Client) storeMessageSecret(info *types.MessageInfo, msg *waProto.Message) {
|
||||
if msgSecret := msg.GetMessageContextInfo().GetMessageSecret(); len(msgSecret) > 0 {
|
||||
err := cli.Store.MsgSecrets.PutMessageSecret(info.Chat, info.Sender, info.ID, msgSecret)
|
||||
if err != nil {
|
||||
@ -511,7 +576,7 @@ func (cli *Client) handleDecryptedMessage(info *types.MessageInfo, msg *waProto.
|
||||
cli.dispatchEvent(evt.UnwrapRaw())
|
||||
}
|
||||
|
||||
func (cli *Client) sendProtocolMessageReceipt(id, msgType string) {
|
||||
func (cli *Client) sendProtocolMessageReceipt(id types.MessageID, msgType types.ReceiptType) {
|
||||
clientID := cli.Store.ID
|
||||
if len(id) == 0 || clientID == nil {
|
||||
return
|
||||
@ -519,8 +584,8 @@ func (cli *Client) sendProtocolMessageReceipt(id, msgType string) {
|
||||
err := cli.sendNode(waBinary.Node{
|
||||
Tag: "receipt",
|
||||
Attrs: waBinary.Attrs{
|
||||
"id": id,
|
||||
"type": msgType,
|
||||
"id": string(id),
|
||||
"type": string(msgType),
|
||||
"to": types.NewJID(clientID.User, types.LegacyUserServer),
|
||||
},
|
||||
Content: nil,
|
||||
|
6
vendor/go.mau.fi/whatsmeow/msgsecret.go
vendored
6
vendor/go.mau.fi/whatsmeow/msgsecret.go
vendored
@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.mau.fi/util/random"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
@ -18,7 +19,6 @@ import (
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
"go.mau.fi/whatsmeow/util/gcmutil"
|
||||
"go.mau.fi/whatsmeow/util/hkdfutil"
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
type MsgSecretType string
|
||||
@ -107,7 +107,7 @@ func (cli *Client) encryptMsgSecret(chat, origSender types.JID, origMsgID types.
|
||||
}
|
||||
secretKey, additionalData := generateMsgSecretKey(useCase, ownID, origMsgID, origSender, baseEncKey)
|
||||
|
||||
iv = randbytes.Make(12)
|
||||
iv = random.Bytes(12)
|
||||
ciphertext, err = gcmutil.Encrypt(secretKey, iv, plaintext, additionalData)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to encrypt secret message: %w", err)
|
||||
@ -221,7 +221,7 @@ func (cli *Client) BuildPollVote(pollInfo *types.MessageInfo, optionNames []stri
|
||||
//
|
||||
// resp, err := cli.SendMessage(context.Background(), chat, cli.BuildPollCreation("meow?", []string{"yes", "no"}, 1))
|
||||
func (cli *Client) BuildPollCreation(name string, optionNames []string, selectableOptionCount int) *waProto.Message {
|
||||
msgSecret := randbytes.Make(32)
|
||||
msgSecret := random.Bytes(32)
|
||||
if selectableOptionCount < 0 || selectableOptionCount > len(optionNames) {
|
||||
selectableOptionCount = 0
|
||||
}
|
||||
|
373
vendor/go.mau.fi/whatsmeow/newsletter.go
vendored
Normal file
373
vendor/go.mau.fi/whatsmeow/newsletter.go
vendored
Normal file
@ -0,0 +1,373 @@
|
||||
// Copyright (c) 2023 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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
)
|
||||
|
||||
// NewsletterSubscribeLiveUpdates subscribes to receive live updates from a WhatsApp channel temporarily (for the duration returned).
|
||||
func (cli *Client) NewsletterSubscribeLiveUpdates(ctx context.Context, jid types.JID) (time.Duration, error) {
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Context: ctx,
|
||||
Namespace: "newsletter",
|
||||
Type: iqSet,
|
||||
To: jid,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "live_updates",
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
child := resp.GetChildByTag("live_updates")
|
||||
dur := child.AttrGetter().Int("duration")
|
||||
return time.Duration(dur) * time.Second, nil
|
||||
}
|
||||
|
||||
// NewsletterMarkViewed marks a channel message as viewed, incrementing the view counter.
|
||||
//
|
||||
// This is not the same as marking the channel as read on your other devices, use the usual MarkRead function for that.
|
||||
func (cli *Client) NewsletterMarkViewed(jid types.JID, serverIDs []types.MessageServerID) error {
|
||||
items := make([]waBinary.Node, len(serverIDs))
|
||||
for i, id := range serverIDs {
|
||||
items[i] = waBinary.Node{
|
||||
Tag: "item",
|
||||
Attrs: waBinary.Attrs{
|
||||
"server_id": id,
|
||||
},
|
||||
}
|
||||
}
|
||||
reqID := cli.generateRequestID()
|
||||
resp := cli.waitResponse(reqID)
|
||||
err := cli.sendNode(waBinary.Node{
|
||||
Tag: "receipt",
|
||||
Attrs: waBinary.Attrs{
|
||||
"to": jid,
|
||||
"type": "view",
|
||||
"id": reqID,
|
||||
},
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "list",
|
||||
Content: items,
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
cli.cancelResponse(reqID, resp)
|
||||
return err
|
||||
}
|
||||
// TODO handle response?
|
||||
<-resp
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewsletterSendReaction sends a reaction to a channel message.
|
||||
// To remove a reaction sent earlier, set reaction to an empty string.
|
||||
//
|
||||
// The last parameter is the message ID of the reaction itself. It can be left empty to let whatsmeow generate a random one.
|
||||
func (cli *Client) NewsletterSendReaction(jid types.JID, serverID types.MessageServerID, reaction string, messageID types.MessageID) error {
|
||||
if messageID == "" {
|
||||
messageID = cli.GenerateMessageID()
|
||||
}
|
||||
reactionAttrs := waBinary.Attrs{}
|
||||
messageAttrs := waBinary.Attrs{
|
||||
"to": jid,
|
||||
"id": messageID,
|
||||
"server_id": serverID,
|
||||
"type": "reaction",
|
||||
}
|
||||
if reaction != "" {
|
||||
reactionAttrs["code"] = reaction
|
||||
} else {
|
||||
messageAttrs["edit"] = string(types.EditAttributeSenderRevoke)
|
||||
}
|
||||
return cli.sendNode(waBinary.Node{
|
||||
Tag: "message",
|
||||
Attrs: messageAttrs,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "reaction",
|
||||
Attrs: reactionAttrs,
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
const (
|
||||
queryFetchNewsletter = "6563316087068696"
|
||||
queryFetchNewsletterDehydrated = "7272540469429201"
|
||||
queryRecommendedNewsletters = "7263823273662354" //variables -> input -> {limit: 20, country_codes: [string]}, output: xwa2_newsletters_recommended
|
||||
queryNewslettersDirectory = "6190824427689257" // variables -> input -> {view: "RECOMMENDED", limit: 50, start_cursor: base64, filters: {country_codes: [string]}}
|
||||
querySubscribedNewsletters = "6388546374527196" // variables -> empty, output: xwa2_newsletter_subscribed
|
||||
queryNewsletterSubscribers = "9800646650009898" //variables -> input -> {newsletter_id, count}, output: xwa2_newsletter_subscribers -> subscribers -> edges
|
||||
mutationMuteNewsletter = "6274038279359549" //variables -> {newsletter_id, updates->{description, settings}}, output: xwa2_newsletter_update -> NewsletterMetadata without viewer meta
|
||||
mutationUnmuteNewsletter = "6068417879924485"
|
||||
mutationUpdateNewsletter = "7150902998257522"
|
||||
mutationCreateNewsletter = "6234210096708695"
|
||||
mutationUnfollowNewsletter = "6392786840836363"
|
||||
mutationFollowNewsletter = "9926858900719341"
|
||||
)
|
||||
|
||||
func (cli *Client) sendMexIQ(ctx context.Context, queryID string, variables any) (json.RawMessage, error) {
|
||||
payload, err := json.Marshal(map[string]any{
|
||||
"variables": variables,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Namespace: "w:mex",
|
||||
Type: iqGet,
|
||||
To: types.ServerJID,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "query",
|
||||
Attrs: waBinary.Attrs{
|
||||
"query_id": queryID,
|
||||
},
|
||||
Content: payload,
|
||||
}},
|
||||
Context: ctx,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, ok := resp.GetOptionalChildByTag("result")
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: "result", In: "mex response"}
|
||||
}
|
||||
resultContent, ok := result.Content.([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected content type %T in mex response", result.Content)
|
||||
}
|
||||
var gqlResp types.GraphQLResponse
|
||||
err = json.Unmarshal(resultContent, &gqlResp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal graphql response: %w", err)
|
||||
} else if len(gqlResp.Errors) > 0 {
|
||||
return gqlResp.Data, fmt.Errorf("graphql error: %w", gqlResp.Errors)
|
||||
}
|
||||
return gqlResp.Data, nil
|
||||
}
|
||||
|
||||
type respGetNewsletterInfo struct {
|
||||
Newsletter *types.NewsletterMetadata `json:"xwa2_newsletter"`
|
||||
}
|
||||
|
||||
func (cli *Client) getNewsletterInfo(input map[string]any, fetchViewerMeta bool) (*types.NewsletterMetadata, error) {
|
||||
data, err := cli.sendMexIQ(context.TODO(), queryFetchNewsletter, map[string]any{
|
||||
"fetch_creation_time": true,
|
||||
"fetch_full_image": true,
|
||||
"fetch_viewer_metadata": fetchViewerMeta,
|
||||
"input": input,
|
||||
})
|
||||
var respData respGetNewsletterInfo
|
||||
if data != nil {
|
||||
jsonErr := json.Unmarshal(data, &respData)
|
||||
if err == nil && jsonErr != nil {
|
||||
err = jsonErr
|
||||
}
|
||||
}
|
||||
return respData.Newsletter, err
|
||||
}
|
||||
|
||||
// GetNewsletterInfo gets the info of a newsletter that you're joined to.
|
||||
func (cli *Client) GetNewsletterInfo(jid types.JID) (*types.NewsletterMetadata, error) {
|
||||
return cli.getNewsletterInfo(map[string]any{
|
||||
"key": jid.String(),
|
||||
"type": types.NewsletterKeyTypeJID,
|
||||
}, true)
|
||||
}
|
||||
|
||||
// GetNewsletterInfoWithInvite gets the info of a newsletter with an invite link.
|
||||
//
|
||||
// You can either pass the full link (https://whatsapp.com/channel/...) or just the `...` part.
|
||||
//
|
||||
// Note that the ViewerMeta field of the returned NewsletterMetadata will be nil.
|
||||
func (cli *Client) GetNewsletterInfoWithInvite(key string) (*types.NewsletterMetadata, error) {
|
||||
return cli.getNewsletterInfo(map[string]any{
|
||||
"key": strings.TrimPrefix(key, NewsletterLinkPrefix),
|
||||
"type": types.NewsletterKeyTypeInvite,
|
||||
}, false)
|
||||
}
|
||||
|
||||
type respGetSubscribedNewsletters struct {
|
||||
Newsletters []*types.NewsletterMetadata `json:"xwa2_newsletter_subscribed"`
|
||||
}
|
||||
|
||||
// GetSubscribedNewsletters gets the info of all newsletters that you're joined to.
|
||||
func (cli *Client) GetSubscribedNewsletters() ([]*types.NewsletterMetadata, error) {
|
||||
data, err := cli.sendMexIQ(context.TODO(), querySubscribedNewsletters, map[string]any{})
|
||||
var respData respGetSubscribedNewsletters
|
||||
if data != nil {
|
||||
jsonErr := json.Unmarshal(data, &respData)
|
||||
if err == nil && jsonErr != nil {
|
||||
err = jsonErr
|
||||
}
|
||||
}
|
||||
return respData.Newsletters, err
|
||||
}
|
||||
|
||||
type CreateNewsletterParams struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Picture []byte `json:"picture,omitempty"`
|
||||
}
|
||||
|
||||
type respCreateNewsletter struct {
|
||||
Newsletter *types.NewsletterMetadata `json:"xwa2_newsletter_create"`
|
||||
}
|
||||
|
||||
// CreateNewsletter creates a new WhatsApp channel.
|
||||
func (cli *Client) CreateNewsletter(params CreateNewsletterParams) (*types.NewsletterMetadata, error) {
|
||||
resp, err := cli.sendMexIQ(context.TODO(), mutationCreateNewsletter, map[string]any{
|
||||
"newsletter_input": ¶ms,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var respData respCreateNewsletter
|
||||
err = json.Unmarshal(resp, &respData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return respData.Newsletter, nil
|
||||
}
|
||||
|
||||
// AcceptTOSNotice accepts a ToS notice.
|
||||
//
|
||||
// To accept the terms for creating newsletters, use
|
||||
//
|
||||
// cli.AcceptTOSNotice("20601218", "5")
|
||||
func (cli *Client) AcceptTOSNotice(noticeID, stage string) error {
|
||||
_, err := cli.sendIQ(infoQuery{
|
||||
Namespace: "tos",
|
||||
Type: iqSet,
|
||||
To: types.ServerJID,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "notice",
|
||||
Attrs: waBinary.Attrs{
|
||||
"id": noticeID,
|
||||
"stage": stage,
|
||||
},
|
||||
}},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// NewsletterToggleMute changes the mute status of a newsletter.
|
||||
func (cli *Client) NewsletterToggleMute(jid types.JID, mute bool) error {
|
||||
query := mutationUnmuteNewsletter
|
||||
if mute {
|
||||
query = mutationMuteNewsletter
|
||||
}
|
||||
_, err := cli.sendMexIQ(context.TODO(), query, map[string]any{
|
||||
"newsletter_id": jid.String(),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// FollowNewsletter makes the user follow (join) a WhatsApp channel.
|
||||
func (cli *Client) FollowNewsletter(jid types.JID) error {
|
||||
_, err := cli.sendMexIQ(context.TODO(), mutationFollowNewsletter, map[string]any{
|
||||
"newsletter_id": jid.String(),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// UnfollowNewsletter makes the user unfollow (leave) a WhatsApp channel.
|
||||
func (cli *Client) UnfollowNewsletter(jid types.JID) error {
|
||||
_, err := cli.sendMexIQ(context.TODO(), mutationUnfollowNewsletter, map[string]any{
|
||||
"newsletter_id": jid.String(),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
type GetNewsletterMessagesParams struct {
|
||||
Count int
|
||||
Before types.MessageServerID
|
||||
}
|
||||
|
||||
// GetNewsletterMessages gets messages in a WhatsApp channel.
|
||||
func (cli *Client) GetNewsletterMessages(jid types.JID, params *GetNewsletterMessagesParams) ([]*types.NewsletterMessage, error) {
|
||||
attrs := waBinary.Attrs{
|
||||
"type": "jid",
|
||||
"jid": jid,
|
||||
}
|
||||
if params != nil {
|
||||
if params.Count != 0 {
|
||||
attrs["count"] = params.Count
|
||||
}
|
||||
if params.Before != 0 {
|
||||
attrs["before"] = params.Before
|
||||
}
|
||||
}
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Namespace: "newsletter",
|
||||
Type: iqGet,
|
||||
To: types.ServerJID,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "messages",
|
||||
Attrs: attrs,
|
||||
}},
|
||||
Context: context.TODO(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messages, ok := resp.GetOptionalChildByTag("messages")
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: "messages", In: "newsletter messages response"}
|
||||
}
|
||||
return cli.parseNewsletterMessages(&messages), nil
|
||||
}
|
||||
|
||||
type GetNewsletterUpdatesParams struct {
|
||||
Count int
|
||||
Since time.Time
|
||||
After types.MessageServerID
|
||||
}
|
||||
|
||||
// GetNewsletterMessageUpdates gets updates in a WhatsApp channel.
|
||||
//
|
||||
// These are the same kind of updates that NewsletterSubscribeLiveUpdates triggers (reaction and view counts).
|
||||
func (cli *Client) GetNewsletterMessageUpdates(jid types.JID, params *GetNewsletterUpdatesParams) ([]*types.NewsletterMessage, error) {
|
||||
attrs := waBinary.Attrs{}
|
||||
if params != nil {
|
||||
if params.Count != 0 {
|
||||
attrs["count"] = params.Count
|
||||
}
|
||||
if !params.Since.IsZero() {
|
||||
attrs["since"] = params.Since.Unix()
|
||||
}
|
||||
if params.After != 0 {
|
||||
attrs["after"] = params.After
|
||||
}
|
||||
}
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Namespace: "newsletter",
|
||||
Type: iqGet,
|
||||
To: jid,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "message_updates",
|
||||
Attrs: attrs,
|
||||
}},
|
||||
Context: context.TODO(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messages, ok := resp.GetOptionalChildByTag("message_updates", "messages")
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: "messages", In: "newsletter messages response"}
|
||||
}
|
||||
return cli.parseNewsletterMessages(&messages), nil
|
||||
}
|
144
vendor/go.mau.fi/whatsmeow/notification.go
vendored
144
vendor/go.mau.fi/whatsmeow/notification.go
vendored
@ -7,10 +7,14 @@
|
||||
package whatsmeow
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.mau.fi/whatsmeow/appstate"
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/store"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
@ -100,7 +104,7 @@ func (cli *Client) handleDeviceNotification(node *waBinary.Node) {
|
||||
cli.Log.Debugf("No device list cached for %s, ignoring device list notification", from)
|
||||
return
|
||||
}
|
||||
cachedParticipantHash := participantListHashV2(cached)
|
||||
cachedParticipantHash := participantListHashV2(cached.devices)
|
||||
for _, child := range node.GetChildren() {
|
||||
if child.Tag != "add" && child.Tag != "remove" {
|
||||
cli.Log.Debugf("Unknown device list change tag %s", child.Tag)
|
||||
@ -112,17 +116,17 @@ func (cli *Client) handleDeviceNotification(node *waBinary.Node) {
|
||||
changedDeviceJID := deviceChild.AttrGetter().JID("jid")
|
||||
switch child.Tag {
|
||||
case "add":
|
||||
cached = append(cached, changedDeviceJID)
|
||||
cached.devices = append(cached.devices, changedDeviceJID)
|
||||
case "remove":
|
||||
for i, jid := range cached {
|
||||
for i, jid := range cached.devices {
|
||||
if jid == changedDeviceJID {
|
||||
cached = append(cached[:i], cached[i+1:]...)
|
||||
cached.devices = append(cached.devices[:i], cached.devices[i+1:]...)
|
||||
}
|
||||
}
|
||||
case "update":
|
||||
// ???
|
||||
}
|
||||
newParticipantHash := participantListHashV2(cached)
|
||||
newParticipantHash := participantListHashV2(cached.devices)
|
||||
if newParticipantHash == deviceHash {
|
||||
cli.Log.Debugf("%s's device list hash changed from %s to %s (%s). New hash matches", from, cachedParticipantHash, deviceHash, child.Tag)
|
||||
cli.userDevicesCache[from] = cached
|
||||
@ -133,6 +137,14 @@ func (cli *Client) handleDeviceNotification(node *waBinary.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) handleFBDeviceNotification(node *waBinary.Node) {
|
||||
cli.userDevicesCacheLock.Lock()
|
||||
defer cli.userDevicesCacheLock.Unlock()
|
||||
jid := node.AttrGetter().JID("from")
|
||||
userDevices := parseFBDeviceList(jid, node.GetChildByTag("devices"))
|
||||
cli.userDevicesCache[jid] = userDevices
|
||||
}
|
||||
|
||||
func (cli *Client) handleOwnDevicesNotification(node *waBinary.Node) {
|
||||
cli.userDevicesCacheLock.Lock()
|
||||
defer cli.userDevicesCacheLock.Unlock()
|
||||
@ -146,13 +158,12 @@ func (cli *Client) handleOwnDevicesNotification(node *waBinary.Node) {
|
||||
cli.Log.Debugf("Ignoring own device change notification, device list not cached")
|
||||
return
|
||||
}
|
||||
oldHash := participantListHashV2(cached)
|
||||
oldHash := participantListHashV2(cached.devices)
|
||||
expectedNewHash := node.AttrGetter().String("dhash")
|
||||
var newDeviceList []types.JID
|
||||
for _, child := range node.GetChildren() {
|
||||
jid := child.AttrGetter().JID("jid")
|
||||
if child.Tag == "device" && !jid.IsEmpty() {
|
||||
jid.AD = true
|
||||
newDeviceList = append(newDeviceList, jid)
|
||||
}
|
||||
}
|
||||
@ -162,10 +173,32 @@ func (cli *Client) handleOwnDevicesNotification(node *waBinary.Node) {
|
||||
delete(cli.userDevicesCache, ownID)
|
||||
} else {
|
||||
cli.Log.Debugf("Received own device list change notification %s -> %s", oldHash, newHash)
|
||||
cli.userDevicesCache[ownID] = newDeviceList
|
||||
cli.userDevicesCache[ownID] = deviceCache{devices: newDeviceList, dhash: expectedNewHash}
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) handleBlocklist(node *waBinary.Node) {
|
||||
ag := node.AttrGetter()
|
||||
evt := events.Blocklist{
|
||||
Action: events.BlocklistAction(ag.OptionalString("action")),
|
||||
DHash: ag.String("dhash"),
|
||||
PrevDHash: ag.OptionalString("prev_dhash"),
|
||||
}
|
||||
for _, child := range node.GetChildren() {
|
||||
ag := child.AttrGetter()
|
||||
change := events.BlocklistChange{
|
||||
JID: ag.JID("jid"),
|
||||
Action: events.BlocklistChangeAction(ag.String("action")),
|
||||
}
|
||||
if !ag.OK() {
|
||||
cli.Log.Warnf("Unexpected data in blocklist event child %v: %v", child.XMLString(), ag.Error())
|
||||
continue
|
||||
}
|
||||
evt.Changes = append(evt.Changes, change)
|
||||
}
|
||||
cli.dispatchEvent(&evt)
|
||||
}
|
||||
|
||||
func (cli *Client) handleAccountSyncNotification(node *waBinary.Node) {
|
||||
for _, child := range node.GetChildren() {
|
||||
switch child.Tag {
|
||||
@ -178,6 +211,8 @@ func (cli *Client) handleAccountSyncNotification(node *waBinary.Node) {
|
||||
Timestamp: node.AttrGetter().UnixTime("t"),
|
||||
JID: cli.getOwnID().ToNonAD(),
|
||||
})
|
||||
case "blocklist":
|
||||
cli.handleBlocklist(&child)
|
||||
default:
|
||||
cli.Log.Debugf("Unhandled account sync item %s", child.Tag)
|
||||
}
|
||||
@ -230,6 +265,93 @@ func (cli *Client) handlePrivacyTokenNotification(node *waBinary.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) parseNewsletterMessages(node *waBinary.Node) []*types.NewsletterMessage {
|
||||
children := node.GetChildren()
|
||||
output := make([]*types.NewsletterMessage, 0, len(children))
|
||||
for _, child := range children {
|
||||
if child.Tag != "message" {
|
||||
continue
|
||||
}
|
||||
msg := types.NewsletterMessage{
|
||||
MessageServerID: child.AttrGetter().Int("server_id"),
|
||||
ViewsCount: 0,
|
||||
ReactionCounts: nil,
|
||||
}
|
||||
for _, subchild := range child.GetChildren() {
|
||||
switch subchild.Tag {
|
||||
case "plaintext":
|
||||
byteContent, ok := subchild.Content.([]byte)
|
||||
if ok {
|
||||
msg.Message = new(waProto.Message)
|
||||
err := proto.Unmarshal(byteContent, msg.Message)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Failed to unmarshal newsletter message: %v", err)
|
||||
msg.Message = nil
|
||||
}
|
||||
}
|
||||
case "views_count":
|
||||
msg.ViewsCount = subchild.AttrGetter().Int("count")
|
||||
case "reactions":
|
||||
msg.ReactionCounts = make(map[string]int)
|
||||
for _, reaction := range subchild.GetChildren() {
|
||||
rag := reaction.AttrGetter()
|
||||
msg.ReactionCounts[rag.String("code")] = rag.Int("count")
|
||||
}
|
||||
}
|
||||
}
|
||||
output = append(output, &msg)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func (cli *Client) handleNewsletterNotification(node *waBinary.Node) {
|
||||
ag := node.AttrGetter()
|
||||
liveUpdates := node.GetChildByTag("live_updates")
|
||||
cli.dispatchEvent(&events.NewsletterLiveUpdate{
|
||||
JID: ag.JID("from"),
|
||||
Time: ag.UnixTime("t"),
|
||||
Messages: cli.parseNewsletterMessages(&liveUpdates),
|
||||
})
|
||||
}
|
||||
|
||||
type newsLetterEventWrapper struct {
|
||||
Data newsletterEvent `json:"data"`
|
||||
}
|
||||
|
||||
type newsletterEvent struct {
|
||||
Join *events.NewsletterJoin `json:"xwa2_notify_newsletter_on_join"`
|
||||
Leave *events.NewsletterLeave `json:"xwa2_notify_newsletter_on_leave"`
|
||||
MuteChange *events.NewsletterMuteChange `json:"xwa2_notify_newsletter_on_mute_change"`
|
||||
// _on_admin_metadata_update -> id, thread_metadata, messages
|
||||
// _on_metadata_update
|
||||
// _on_state_change -> id, is_requestor, state
|
||||
}
|
||||
|
||||
func (cli *Client) handleMexNotification(node *waBinary.Node) {
|
||||
for _, child := range node.GetChildren() {
|
||||
if child.Tag != "update" {
|
||||
continue
|
||||
}
|
||||
childData, ok := child.Content.([]byte)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var wrapper newsLetterEventWrapper
|
||||
err := json.Unmarshal(childData, &wrapper)
|
||||
if err != nil {
|
||||
cli.Log.Errorf("Failed to unmarshal JSON in mex event: %v", err)
|
||||
continue
|
||||
}
|
||||
if wrapper.Data.Join != nil {
|
||||
cli.dispatchEvent(wrapper.Data.Join)
|
||||
} else if wrapper.Data.Leave != nil {
|
||||
cli.dispatchEvent(wrapper.Data.Leave)
|
||||
} else if wrapper.Data.MuteChange != nil {
|
||||
cli.dispatchEvent(wrapper.Data.MuteChange)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) handleNotification(node *waBinary.Node) {
|
||||
ag := node.AttrGetter()
|
||||
notifType := ag.String("type")
|
||||
@ -246,6 +368,8 @@ func (cli *Client) handleNotification(node *waBinary.Node) {
|
||||
go cli.handleAccountSyncNotification(node)
|
||||
case "devices":
|
||||
go cli.handleDeviceNotification(node)
|
||||
case "fbid:devices":
|
||||
go cli.handleFBDeviceNotification(node)
|
||||
case "w:gp2":
|
||||
evt, err := cli.parseGroupNotification(node)
|
||||
if err != nil {
|
||||
@ -261,6 +385,10 @@ func (cli *Client) handleNotification(node *waBinary.Node) {
|
||||
go cli.handlePrivacyTokenNotification(node)
|
||||
case "link_code_companion_reg":
|
||||
go cli.tryHandleCodePairNotification(node)
|
||||
case "newsletter":
|
||||
go cli.handleNewsletterNotification(node)
|
||||
case "mex":
|
||||
go cli.handleMexNotification(node)
|
||||
// Other types: business, disappearing_mode, server, status, pay, psa
|
||||
default:
|
||||
cli.Log.Debugf("Unhandled notification with type %s", notifType)
|
||||
|
51
vendor/go.mau.fi/whatsmeow/pair-code.go
vendored
51
vendor/go.mau.fi/whatsmeow/pair-code.go
vendored
@ -15,16 +15,14 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"go.mau.fi/util/random"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/store"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/util/hkdfutil"
|
||||
"go.mau.fi/whatsmeow/util/keys"
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
// PairClientType is the type of client to use with PairCode.
|
||||
@ -44,29 +42,6 @@ const (
|
||||
PairClientOtherWebClient
|
||||
)
|
||||
|
||||
func platformTypeToPairClientType(platformType waProto.DeviceProps_PlatformType) PairClientType {
|
||||
switch platformType {
|
||||
case waProto.DeviceProps_CHROME:
|
||||
return PairClientChrome
|
||||
case waProto.DeviceProps_EDGE:
|
||||
return PairClientEdge
|
||||
case waProto.DeviceProps_FIREFOX:
|
||||
return PairClientFirefox
|
||||
case waProto.DeviceProps_IE:
|
||||
return PairClientIE
|
||||
case waProto.DeviceProps_OPERA:
|
||||
return PairClientOpera
|
||||
case waProto.DeviceProps_SAFARI:
|
||||
return PairClientSafari
|
||||
case waProto.DeviceProps_DESKTOP:
|
||||
return PairClientElectron
|
||||
case waProto.DeviceProps_UWP:
|
||||
return PairClientUWP
|
||||
default:
|
||||
return PairClientOtherWebClient
|
||||
}
|
||||
}
|
||||
|
||||
var notNumbers = regexp.MustCompile("[^0-9]")
|
||||
var linkingBase32 = base32.NewEncoding("123456789ABCDEFGHJKLMNPQRSTVWXYZ")
|
||||
|
||||
@ -79,9 +54,9 @@ type phoneLinkingCache struct {
|
||||
|
||||
func generateCompanionEphemeralKey() (ephemeralKeyPair *keys.KeyPair, ephemeralKey []byte, encodedLinkingCode string) {
|
||||
ephemeralKeyPair = keys.NewKeyPair()
|
||||
salt := randbytes.Make(32)
|
||||
iv := randbytes.Make(16)
|
||||
linkingCode := randbytes.Make(5)
|
||||
salt := random.Bytes(32)
|
||||
iv := random.Bytes(16)
|
||||
linkingCode := random.Bytes(5)
|
||||
encodedLinkingCode = linkingBase32.EncodeToString(linkingCode)
|
||||
linkCodeKey := pbkdf2.Key([]byte(encodedLinkingCode), salt, 2<<16, 32, sha256.New)
|
||||
linkCipherBlock, _ := aes.NewCipher(linkCodeKey)
|
||||
@ -96,15 +71,19 @@ func generateCompanionEphemeralKey() (ephemeralKeyPair *keys.KeyPair, ephemeralK
|
||||
|
||||
// PairPhone generates a pairing code that can be used to link to a phone without scanning a QR code.
|
||||
//
|
||||
// You must connect the client normally before calling this (which means you'll also receive a QR code
|
||||
// event, but that can be ignored when doing code pairing).
|
||||
//
|
||||
// The exact expiry of pairing codes is unknown, but QR codes are always generated and the login websocket is closed
|
||||
// after the QR codes run out, which means there's a 160-second time limit. It is recommended to generate the pairing
|
||||
// code immediately after connecting to the websocket to have the maximum time.
|
||||
//
|
||||
// The clientType parameter must be one of the PairClient* constants, but which one doesn't matter.
|
||||
// The client display name must be formatted as `Browser (OS)`, and only common browsers/OSes are allowed
|
||||
// (the server will validate it and return 400 if it's wrong).
|
||||
//
|
||||
// See https://faq.whatsapp.com/1324084875126592 for more info
|
||||
func (cli *Client) PairPhone(phone string, showPushNotification bool) (string, error) {
|
||||
clientType := platformTypeToPairClientType(store.DeviceProps.GetPlatformType())
|
||||
clientDisplayName := store.DeviceProps.GetOs()
|
||||
|
||||
func (cli *Client) PairPhone(phone string, showPushNotification bool, clientType PairClientType, clientDisplayName string) (string, error) {
|
||||
ephemeralKeyPair, ephemeralKey, encodedLinkingCode := generateCompanionEphemeralKey()
|
||||
phone = notNumbers.ReplaceAllString(phone, "")
|
||||
jid := types.NewJID(phone, types.DefaultUserServer)
|
||||
@ -187,9 +166,9 @@ func (cli *Client) handleCodePairNotification(parentNode *waBinary.Node) error {
|
||||
}
|
||||
}
|
||||
|
||||
advSecretRandom := randbytes.Make(32)
|
||||
keyBundleSalt := randbytes.Make(32)
|
||||
keyBundleNonce := randbytes.Make(12)
|
||||
advSecretRandom := random.Bytes(32)
|
||||
keyBundleSalt := random.Bytes(32)
|
||||
keyBundleNonce := random.Bytes(12)
|
||||
|
||||
// Decrypt the primary device's ephemeral public key, which was encrypted with the 8-character pairing code,
|
||||
// then compute the DH shared secret using our ephemeral private key we generated earlier.
|
||||
|
1
vendor/go.mau.fi/whatsmeow/prekeys.go
vendored
1
vendor/go.mau.fi/whatsmeow/prekeys.go
vendored
@ -125,7 +125,6 @@ func (cli *Client) fetchPreKeys(ctx context.Context, users []types.JID) (map[typ
|
||||
continue
|
||||
}
|
||||
jid := child.AttrGetter().JID("jid")
|
||||
jid.AD = true
|
||||
bundle, err := nodeToPreKeyBundle(uint32(jid.Device), child)
|
||||
respData[jid] = preKeyResp{bundle, err}
|
||||
}
|
||||
|
5
vendor/go.mau.fi/whatsmeow/presence.go
vendored
5
vendor/go.mau.fi/whatsmeow/presence.go
vendored
@ -8,7 +8,6 @@ package whatsmeow
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
@ -66,9 +65,9 @@ func (cli *Client) SendPresence(state types.Presence) error {
|
||||
return ErrNoPushName
|
||||
}
|
||||
if state == types.PresenceAvailable {
|
||||
atomic.CompareAndSwapUint32(&cli.sendActiveReceipts, 0, 1)
|
||||
cli.sendActiveReceipts.CompareAndSwap(0, 1)
|
||||
} else {
|
||||
atomic.CompareAndSwapUint32(&cli.sendActiveReceipts, 1, 0)
|
||||
cli.sendActiveReceipts.CompareAndSwap(1, 0)
|
||||
}
|
||||
return cli.sendNode(waBinary.Node{
|
||||
Tag: "presence",
|
||||
|
88
vendor/go.mau.fi/whatsmeow/privacysettings.go
vendored
88
vendor/go.mau.fi/whatsmeow/privacysettings.go
vendored
@ -7,6 +7,9 @@
|
||||
package whatsmeow
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
@ -39,6 +42,9 @@ func (cli *Client) TryFetchPrivacySettings(ignoreCache bool) (*types.PrivacySett
|
||||
// GetPrivacySettings will get the user's privacy settings. If an error occurs while fetching them, the error will be
|
||||
// logged, but the method will just return an empty struct.
|
||||
func (cli *Client) GetPrivacySettings() (settings types.PrivacySettings) {
|
||||
if cli.MessengerConfig != nil {
|
||||
return
|
||||
}
|
||||
settingsPtr, err := cli.TryFetchPrivacySettings(false)
|
||||
if err != nil {
|
||||
cli.Log.Errorf("Failed to fetch privacy settings: %v", err)
|
||||
@ -48,6 +54,69 @@ func (cli *Client) GetPrivacySettings() (settings types.PrivacySettings) {
|
||||
return
|
||||
}
|
||||
|
||||
// SetPrivacySetting will set the given privacy setting to the given value.
|
||||
// The privacy settings will be fetched from the server after the change and the new settings will be returned.
|
||||
// If an error occurs while fetching the new settings, will return an empty struct.
|
||||
func (cli *Client) SetPrivacySetting(name types.PrivacySettingType, value types.PrivacySetting) (settings types.PrivacySettings, err error) {
|
||||
settingsPtr, err := cli.TryFetchPrivacySettings(false)
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
_, err = cli.sendIQ(infoQuery{
|
||||
Namespace: "privacy",
|
||||
Type: iqSet,
|
||||
To: types.ServerJID,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "privacy",
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "category",
|
||||
Attrs: waBinary.Attrs{
|
||||
"name": string(name),
|
||||
"value": string(value),
|
||||
},
|
||||
}},
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings = *settingsPtr
|
||||
switch name {
|
||||
case types.PrivacySettingTypeGroupAdd:
|
||||
settings.GroupAdd = value
|
||||
case types.PrivacySettingTypeLastSeen:
|
||||
settings.LastSeen = value
|
||||
case types.PrivacySettingTypeStatus:
|
||||
settings.Status = value
|
||||
case types.PrivacySettingTypeProfile:
|
||||
settings.Profile = value
|
||||
case types.PrivacySettingTypeReadReceipts:
|
||||
settings.ReadReceipts = value
|
||||
case types.PrivacySettingTypeOnline:
|
||||
settings.Online = value
|
||||
case types.PrivacySettingTypeCallAdd:
|
||||
settings.CallAdd = value
|
||||
}
|
||||
cli.privacySettingsCache.Store(&settings)
|
||||
return
|
||||
}
|
||||
|
||||
// SetDefaultDisappearingTimer will set the default disappearing message timer.
|
||||
func (cli *Client) SetDefaultDisappearingTimer(timer time.Duration) (err error) {
|
||||
_, err = cli.sendIQ(infoQuery{
|
||||
Namespace: "disappearing_mode",
|
||||
Type: iqSet,
|
||||
To: types.ServerJID,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "disappearing_mode",
|
||||
Attrs: waBinary.Attrs{
|
||||
"duration": strconv.Itoa(int(timer.Seconds())),
|
||||
},
|
||||
}},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) parsePrivacySettings(privacyNode *waBinary.Node, settings *types.PrivacySettings) *events.PrivacySettings {
|
||||
var evt events.PrivacySettings
|
||||
for _, child := range privacyNode.GetChildren() {
|
||||
@ -55,24 +124,30 @@ func (cli *Client) parsePrivacySettings(privacyNode *waBinary.Node, settings *ty
|
||||
continue
|
||||
}
|
||||
ag := child.AttrGetter()
|
||||
name := ag.String("name")
|
||||
name := types.PrivacySettingType(ag.String("name"))
|
||||
value := types.PrivacySetting(ag.String("value"))
|
||||
switch name {
|
||||
case "groupadd":
|
||||
case types.PrivacySettingTypeGroupAdd:
|
||||
settings.GroupAdd = value
|
||||
evt.GroupAddChanged = true
|
||||
case "last":
|
||||
case types.PrivacySettingTypeLastSeen:
|
||||
settings.LastSeen = value
|
||||
evt.LastSeenChanged = true
|
||||
case "status":
|
||||
case types.PrivacySettingTypeStatus:
|
||||
settings.Status = value
|
||||
evt.StatusChanged = true
|
||||
case "profile":
|
||||
case types.PrivacySettingTypeProfile:
|
||||
settings.Profile = value
|
||||
evt.ProfileChanged = true
|
||||
case "readreceipts":
|
||||
case types.PrivacySettingTypeReadReceipts:
|
||||
settings.ReadReceipts = value
|
||||
evt.ReadReceiptsChanged = true
|
||||
case types.PrivacySettingTypeOnline:
|
||||
settings.Online = value
|
||||
evt.OnlineChanged = true
|
||||
case types.PrivacySettingTypeCallAdd:
|
||||
settings.CallAdd = value
|
||||
evt.CallAddChanged = true
|
||||
}
|
||||
}
|
||||
return &evt
|
||||
@ -83,6 +158,7 @@ func (cli *Client) handlePrivacySettingsNotification(privacyNode *waBinary.Node)
|
||||
settings, err := cli.TryFetchPrivacySettings(false)
|
||||
if err != nil {
|
||||
cli.Log.Errorf("Failed to fetch privacy settings when handling change: %v", err)
|
||||
return
|
||||
}
|
||||
evt := cli.parsePrivacySettings(privacyNode, settings)
|
||||
// The data isn't be reliable if the fetch failed, so only cache if it didn't fail
|
||||
|
41
vendor/go.mau.fi/whatsmeow/receipt.go
vendored
41
vendor/go.mau.fi/whatsmeow/receipt.go
vendored
@ -8,7 +8,6 @@ package whatsmeow
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
@ -21,7 +20,7 @@ func (cli *Client) handleReceipt(node *waBinary.Node) {
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Failed to parse receipt: %v", err)
|
||||
} else if receipt != nil {
|
||||
if receipt.Type == events.ReceiptTypeRetry {
|
||||
if receipt.Type == types.ReceiptTypeRetry {
|
||||
go func() {
|
||||
err := cli.handleRetryReceipt(receipt, node)
|
||||
if err != nil {
|
||||
@ -63,7 +62,7 @@ func (cli *Client) parseReceipt(node *waBinary.Node) (*events.Receipt, error) {
|
||||
receipt := events.Receipt{
|
||||
MessageSource: source,
|
||||
Timestamp: ag.UnixTime("t"),
|
||||
Type: events.ReceiptType(ag.OptionalString("type")),
|
||||
Type: types.ReceiptType(ag.OptionalString("type")),
|
||||
}
|
||||
if source.IsGroup && source.Sender.IsEmpty() {
|
||||
participantTags := node.GetChildrenByTag("participants")
|
||||
@ -127,20 +126,36 @@ func (cli *Client) sendAck(node *waBinary.Node) {
|
||||
//
|
||||
// You can mark multiple messages as read at the same time, but only if the messages were sent by the same user.
|
||||
// To mark messages by different users as read, you must call MarkRead multiple times (once for each user).
|
||||
func (cli *Client) MarkRead(ids []types.MessageID, timestamp time.Time, chat, sender types.JID) error {
|
||||
//
|
||||
// To mark a voice message as played, specify types.ReceiptTypePlayed as the last parameter.
|
||||
// Providing more than one receipt type will panic: the parameter is only a vararg for backwards compatibility.
|
||||
func (cli *Client) MarkRead(ids []types.MessageID, timestamp time.Time, chat, sender types.JID, receiptTypeExtra ...types.ReceiptType) error {
|
||||
if len(ids) == 0 {
|
||||
return fmt.Errorf("no message IDs specified")
|
||||
}
|
||||
receiptType := types.ReceiptTypeRead
|
||||
if len(receiptTypeExtra) == 1 {
|
||||
receiptType = receiptTypeExtra[0]
|
||||
} else if len(receiptTypeExtra) > 1 {
|
||||
panic(fmt.Errorf("too many receipt types specified"))
|
||||
}
|
||||
node := waBinary.Node{
|
||||
Tag: "receipt",
|
||||
Attrs: waBinary.Attrs{
|
||||
"id": ids[0],
|
||||
"type": "read",
|
||||
"type": string(receiptType),
|
||||
"to": chat,
|
||||
"t": timestamp.Unix(),
|
||||
},
|
||||
}
|
||||
if cli.GetPrivacySettings().ReadReceipts == types.PrivacySettingNone {
|
||||
node.Attrs["type"] = "read-self"
|
||||
if chat.Server == types.NewsletterServer || cli.GetPrivacySettings().ReadReceipts == types.PrivacySettingNone {
|
||||
switch receiptType {
|
||||
case types.ReceiptTypeRead:
|
||||
node.Attrs["type"] = string(types.ReceiptTypeReadSelf)
|
||||
// TODO change played to played-self?
|
||||
}
|
||||
}
|
||||
if !sender.IsEmpty() && chat.Server != types.DefaultUserServer {
|
||||
if !sender.IsEmpty() && chat.Server != types.DefaultUserServer && chat.Server != types.MessengerServer {
|
||||
node.Attrs["participant"] = sender.ToNonAD()
|
||||
}
|
||||
if len(ids) > 1 {
|
||||
@ -174,9 +189,9 @@ func (cli *Client) MarkRead(ids []types.MessageID, timestamp time.Time, chat, se
|
||||
// receipts will act like the client is offline until SendPresence is called again.
|
||||
func (cli *Client) SetForceActiveDeliveryReceipts(active bool) {
|
||||
if active {
|
||||
atomic.StoreUint32(&cli.sendActiveReceipts, 2)
|
||||
cli.sendActiveReceipts.Store(2)
|
||||
} else {
|
||||
atomic.StoreUint32(&cli.sendActiveReceipts, 0)
|
||||
cli.sendActiveReceipts.Store(0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,9 +200,9 @@ func (cli *Client) sendMessageReceipt(info *types.MessageInfo) {
|
||||
"id": info.ID,
|
||||
}
|
||||
if info.IsFromMe {
|
||||
attrs["type"] = "sender"
|
||||
} else if atomic.LoadUint32(&cli.sendActiveReceipts) == 0 {
|
||||
attrs["type"] = "inactive"
|
||||
attrs["type"] = string(types.ReceiptTypeSender)
|
||||
} else if cli.sendActiveReceipts.Load() == 0 {
|
||||
attrs["type"] = string(types.ReceiptTypeInactive)
|
||||
}
|
||||
attrs["to"] = info.Chat
|
||||
if info.IsGroup {
|
||||
|
7
vendor/go.mau.fi/whatsmeow/request.go
vendored
7
vendor/go.mau.fi/whatsmeow/request.go
vendored
@ -10,7 +10,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
@ -18,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func (cli *Client) generateRequestID() string {
|
||||
return cli.uniqueID + strconv.FormatUint(uint64(atomic.AddUint32(&cli.idCounter, 1)), 10)
|
||||
return cli.uniqueID + strconv.FormatUint(cli.idCounter.Add(1), 10)
|
||||
}
|
||||
|
||||
var xmlStreamEndNode = &waBinary.Node{Tag: "xmlstreamend"}
|
||||
@ -139,13 +138,15 @@ func (cli *Client) sendIQAsync(query infoQuery) (<-chan *waBinary.Node, error) {
|
||||
return ch, err
|
||||
}
|
||||
|
||||
const defaultRequestTimeout = 75 * time.Second
|
||||
|
||||
func (cli *Client) sendIQ(query infoQuery) (*waBinary.Node, error) {
|
||||
resChan, data, err := cli.sendIQAsyncAndGetData(&query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if query.Timeout == 0 {
|
||||
query.Timeout = 75 * time.Second
|
||||
query.Timeout = defaultRequestTimeout
|
||||
}
|
||||
if query.Context == nil {
|
||||
query.Context = context.Background()
|
||||
|
160
vendor/go.mau.fi/whatsmeow/retry.go
vendored
160
vendor/go.mau.fi/whatsmeow/retry.go
vendored
@ -8,6 +8,8 @@ package whatsmeow
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
@ -19,6 +21,10 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waCommon"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMsgApplication"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMsgTransport"
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
@ -32,19 +38,22 @@ type recentMessageKey struct {
|
||||
ID types.MessageID
|
||||
}
|
||||
|
||||
// RecentMessage contains the info needed to re-send a message when another device fails to decrypt it.
|
||||
type RecentMessage struct {
|
||||
Proto *waProto.Message
|
||||
Timestamp time.Time
|
||||
wa *waProto.Message
|
||||
fb *waMsgApplication.MessageApplication
|
||||
}
|
||||
|
||||
func (cli *Client) addRecentMessage(to types.JID, id types.MessageID, message *waProto.Message) {
|
||||
func (rm RecentMessage) IsEmpty() bool {
|
||||
return rm.wa == nil && rm.fb == nil
|
||||
}
|
||||
|
||||
func (cli *Client) addRecentMessage(to types.JID, id types.MessageID, wa *waProto.Message, fb *waMsgApplication.MessageApplication) {
|
||||
cli.recentMessagesLock.Lock()
|
||||
key := recentMessageKey{to, id}
|
||||
if cli.recentMessagesList[cli.recentMessagesPtr].ID != "" {
|
||||
delete(cli.recentMessagesMap, cli.recentMessagesList[cli.recentMessagesPtr])
|
||||
}
|
||||
cli.recentMessagesMap[key] = message
|
||||
cli.recentMessagesMap[key] = RecentMessage{wa: wa, fb: fb}
|
||||
cli.recentMessagesList[cli.recentMessagesPtr] = key
|
||||
cli.recentMessagesPtr++
|
||||
if cli.recentMessagesPtr >= len(cli.recentMessagesList) {
|
||||
@ -53,26 +62,27 @@ func (cli *Client) addRecentMessage(to types.JID, id types.MessageID, message *w
|
||||
cli.recentMessagesLock.Unlock()
|
||||
}
|
||||
|
||||
func (cli *Client) getRecentMessage(to types.JID, id types.MessageID) *waProto.Message {
|
||||
func (cli *Client) getRecentMessage(to types.JID, id types.MessageID) RecentMessage {
|
||||
cli.recentMessagesLock.RLock()
|
||||
msg, _ := cli.recentMessagesMap[recentMessageKey{to, id}]
|
||||
cli.recentMessagesLock.RUnlock()
|
||||
return msg
|
||||
}
|
||||
|
||||
func (cli *Client) getMessageForRetry(receipt *events.Receipt, messageID types.MessageID) (*waProto.Message, error) {
|
||||
func (cli *Client) getMessageForRetry(receipt *events.Receipt, messageID types.MessageID) (RecentMessage, error) {
|
||||
msg := cli.getRecentMessage(receipt.Chat, messageID)
|
||||
if msg == nil {
|
||||
msg = cli.GetMessageForRetry(receipt.Sender, receipt.Chat, messageID)
|
||||
if msg == nil {
|
||||
return nil, fmt.Errorf("couldn't find message %s", messageID)
|
||||
if msg.IsEmpty() {
|
||||
waMsg := cli.GetMessageForRetry(receipt.Sender, receipt.Chat, messageID)
|
||||
if waMsg == nil {
|
||||
return RecentMessage{}, fmt.Errorf("couldn't find message %s", messageID)
|
||||
} else {
|
||||
cli.Log.Debugf("Found message in GetMessageForRetry to accept retry receipt for %s/%s from %s", receipt.Chat, messageID, receipt.Sender)
|
||||
}
|
||||
msg = RecentMessage{wa: waMsg}
|
||||
} else {
|
||||
cli.Log.Debugf("Found message in local cache to accept retry receipt for %s/%s from %s", receipt.Chat, messageID, receipt.Sender)
|
||||
}
|
||||
return proto.Clone(msg).(*waProto.Message), nil
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
const recreateSessionTimeout = 1 * time.Hour
|
||||
@ -94,6 +104,11 @@ func (cli *Client) shouldRecreateSession(retryCount int, jid types.JID) (reason
|
||||
return "", false
|
||||
}
|
||||
|
||||
type incomingRetryKey struct {
|
||||
jid types.JID
|
||||
messageID types.MessageID
|
||||
}
|
||||
|
||||
// handleRetryReceipt handles an incoming retry receipt for an outgoing message.
|
||||
func (cli *Client) handleRetryReceipt(receipt *events.Receipt, node *waBinary.Node) error {
|
||||
retryChild, ok := node.GetOptionalChildByTag("retry")
|
||||
@ -111,40 +126,87 @@ func (cli *Client) handleRetryReceipt(receipt *events.Receipt, node *waBinary.No
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var fbConsumerMsg *waConsumerApplication.ConsumerApplication
|
||||
if msg.fb != nil {
|
||||
subProto, ok := msg.fb.GetPayload().GetSubProtocol().GetSubProtocol().(*waMsgApplication.MessageApplication_SubProtocolPayload_ConsumerMessage)
|
||||
if ok {
|
||||
fbConsumerMsg, err = subProto.Decode()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode consumer message for retry: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retryKey := incomingRetryKey{receipt.Sender, messageID}
|
||||
cli.incomingRetryRequestCounterLock.Lock()
|
||||
cli.incomingRetryRequestCounter[retryKey]++
|
||||
internalCounter := cli.incomingRetryRequestCounter[retryKey]
|
||||
cli.incomingRetryRequestCounterLock.Unlock()
|
||||
if internalCounter >= 10 {
|
||||
cli.Log.Warnf("Dropping retry request from %s for %s: internal retry counter is %d", messageID, receipt.Sender, internalCounter)
|
||||
return nil
|
||||
}
|
||||
|
||||
ownID := cli.getOwnID()
|
||||
if ownID.IsEmpty() {
|
||||
return ErrNotLoggedIn
|
||||
}
|
||||
|
||||
var fbSKDM *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage
|
||||
var fbDSM *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage
|
||||
if receipt.IsGroup {
|
||||
builder := groups.NewGroupSessionBuilder(cli.Store, pbSerializer)
|
||||
senderKeyName := protocol.NewSenderKeyName(receipt.Chat.String(), ownID.SignalAddress())
|
||||
signalSKDMessage, err := builder.Create(senderKeyName)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Failed to create sender key distribution message to include in retry of %s in %s to %s: %v", messageID, receipt.Chat, receipt.Sender, err)
|
||||
} else {
|
||||
msg.SenderKeyDistributionMessage = &waProto.SenderKeyDistributionMessage{
|
||||
}
|
||||
if msg.wa != nil {
|
||||
msg.wa.SenderKeyDistributionMessage = &waProto.SenderKeyDistributionMessage{
|
||||
GroupId: proto.String(receipt.Chat.String()),
|
||||
AxolotlSenderKeyDistributionMessage: signalSKDMessage.Serialize(),
|
||||
}
|
||||
} else {
|
||||
fbSKDM = &waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage{
|
||||
GroupID: receipt.Chat.String(),
|
||||
AxolotlSenderKeyDistributionMessage: signalSKDMessage.Serialize(),
|
||||
}
|
||||
}
|
||||
} else if receipt.IsFromMe {
|
||||
msg = &waProto.Message{
|
||||
DeviceSentMessage: &waProto.DeviceSentMessage{
|
||||
DestinationJid: proto.String(receipt.Chat.String()),
|
||||
Message: msg,
|
||||
},
|
||||
if msg.wa != nil {
|
||||
msg.wa = &waProto.Message{
|
||||
DeviceSentMessage: &waProto.DeviceSentMessage{
|
||||
DestinationJid: proto.String(receipt.Chat.String()),
|
||||
Message: msg.wa,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
fbDSM = &waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage{
|
||||
DestinationJID: receipt.Chat.String(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cli.PreRetryCallback != nil && !cli.PreRetryCallback(receipt, messageID, retryCount, msg) {
|
||||
// TODO pre-retry callback for fb
|
||||
if cli.PreRetryCallback != nil && !cli.PreRetryCallback(receipt, messageID, retryCount, msg.wa) {
|
||||
cli.Log.Debugf("Cancelled retry receipt in PreRetryCallback")
|
||||
return nil
|
||||
}
|
||||
|
||||
plaintext, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal message: %w", err)
|
||||
var plaintext, frankingTag []byte
|
||||
if msg.wa != nil {
|
||||
plaintext, err = proto.Marshal(msg.wa)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal message: %w", err)
|
||||
}
|
||||
} else {
|
||||
plaintext, err = proto.Marshal(msg.fb)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal consumer message: %w", err)
|
||||
}
|
||||
frankingHash := hmac.New(sha256.New, msg.fb.GetMetadata().GetFrankingKey())
|
||||
frankingHash.Write(plaintext)
|
||||
frankingTag = frankingHash.Sum(nil)
|
||||
}
|
||||
_, hasKeys := node.GetOptionalChildByTag("keys")
|
||||
var bundle *prekey.Bundle
|
||||
@ -160,20 +222,39 @@ func (cli *Client) handleRetryReceipt(receipt *events.Receipt, node *waBinary.No
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
senderAD := receipt.Sender
|
||||
senderAD.AD = true
|
||||
bundle, err = keys[senderAD].bundle, keys[senderAD].err
|
||||
bundle, err = keys[receipt.Sender].bundle, keys[receipt.Sender].err
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch prekeys: %w", err)
|
||||
} else if bundle == nil {
|
||||
return fmt.Errorf("didn't get prekey bundle for %s (response size: %d)", senderAD, len(keys))
|
||||
return fmt.Errorf("didn't get prekey bundle for %s (response size: %d)", receipt.Sender, len(keys))
|
||||
}
|
||||
}
|
||||
encAttrs := waBinary.Attrs{}
|
||||
if mediaType := getMediaTypeFromMessage(msg); mediaType != "" {
|
||||
encAttrs["mediatype"] = mediaType
|
||||
var msgAttrs messageAttrs
|
||||
if msg.wa != nil {
|
||||
msgAttrs.MediaType = getMediaTypeFromMessage(msg.wa)
|
||||
msgAttrs.Type = getTypeFromMessage(msg.wa)
|
||||
} else if fbConsumerMsg != nil {
|
||||
msgAttrs = getAttrsFromFBMessage(fbConsumerMsg)
|
||||
} else {
|
||||
msgAttrs.Type = "text"
|
||||
}
|
||||
if msgAttrs.MediaType != "" {
|
||||
encAttrs["mediatype"] = msgAttrs.MediaType
|
||||
}
|
||||
var encrypted *waBinary.Node
|
||||
var includeDeviceIdentity bool
|
||||
if msg.wa != nil {
|
||||
encrypted, includeDeviceIdentity, err = cli.encryptMessageForDevice(plaintext, receipt.Sender, bundle, encAttrs)
|
||||
} else {
|
||||
encrypted, err = cli.encryptMessageForDeviceV3(&waMsgTransport.MessageTransport_Payload{
|
||||
ApplicationPayload: &waCommon.SubProtocol{
|
||||
Payload: plaintext,
|
||||
Version: FBMessageApplicationVersion,
|
||||
},
|
||||
FutureProof: waCommon.FutureProofBehavior_PLACEHOLDER,
|
||||
}, fbSKDM, fbDSM, receipt.Sender, bundle, encAttrs)
|
||||
}
|
||||
encrypted, includeDeviceIdentity, err := cli.encryptMessageForDevice(plaintext, receipt.Sender, bundle, encAttrs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to encrypt message for retry: %w", err)
|
||||
}
|
||||
@ -181,7 +262,7 @@ func (cli *Client) handleRetryReceipt(receipt *events.Receipt, node *waBinary.No
|
||||
|
||||
attrs := waBinary.Attrs{
|
||||
"to": node.Attrs["from"],
|
||||
"type": getTypeFromMessage(msg),
|
||||
"type": msgAttrs.Type,
|
||||
"id": messageID,
|
||||
"t": timestamp.Unix(),
|
||||
}
|
||||
@ -197,10 +278,19 @@ func (cli *Client) handleRetryReceipt(receipt *events.Receipt, node *waBinary.No
|
||||
if edit, ok := node.Attrs["edit"]; ok {
|
||||
attrs["edit"] = edit
|
||||
}
|
||||
var content []waBinary.Node
|
||||
if msg.wa != nil {
|
||||
content = cli.getMessageContent(*encrypted, msg.wa, attrs, includeDeviceIdentity)
|
||||
} else {
|
||||
content = []waBinary.Node{
|
||||
*encrypted,
|
||||
{Tag: "franking", Content: []waBinary.Node{{Tag: "franking_tag", Content: frankingTag}}},
|
||||
}
|
||||
}
|
||||
err = cli.sendNode(waBinary.Node{
|
||||
Tag: "message",
|
||||
Attrs: attrs,
|
||||
Content: cli.getMessageContent(*encrypted, msg, attrs, includeDeviceIdentity),
|
||||
Content: content,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send retry message: %w", err)
|
||||
@ -210,7 +300,7 @@ func (cli *Client) handleRetryReceipt(receipt *events.Receipt, node *waBinary.No
|
||||
}
|
||||
|
||||
func (cli *Client) cancelDelayedRequestFromPhone(msgID types.MessageID) {
|
||||
if !cli.AutomaticMessageRerequestFromPhone {
|
||||
if !cli.AutomaticMessageRerequestFromPhone || cli.MessengerConfig != nil {
|
||||
return
|
||||
}
|
||||
cli.pendingPhoneRerequestsLock.RLock()
|
||||
@ -226,7 +316,7 @@ func (cli *Client) cancelDelayedRequestFromPhone(msgID types.MessageID) {
|
||||
var RequestFromPhoneDelay = 5 * time.Second
|
||||
|
||||
func (cli *Client) delayedRequestMessageFromPhone(info *types.MessageInfo) {
|
||||
if !cli.AutomaticMessageRerequestFromPhone {
|
||||
if !cli.AutomaticMessageRerequestFromPhone || cli.MessengerConfig != nil {
|
||||
return
|
||||
}
|
||||
cli.pendingPhoneRerequestsLock.Lock()
|
||||
@ -253,7 +343,7 @@ func (cli *Client) delayedRequestMessageFromPhone(info *types.MessageInfo) {
|
||||
}
|
||||
_, err := cli.SendMessage(
|
||||
ctx,
|
||||
cli.Store.ID.ToNonAD(),
|
||||
cli.getOwnID().ToNonAD(),
|
||||
cli.BuildUnavailableMessageRequest(info.Chat, info.Sender, info.ID),
|
||||
SendRequestExtra{Peer: true},
|
||||
)
|
||||
|
161
vendor/go.mau.fi/whatsmeow/send.go
vendored
161
vendor/go.mau.fi/whatsmeow/send.go
vendored
@ -19,19 +19,19 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.mau.fi/libsignal/signalerror"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"go.mau.fi/libsignal/groups"
|
||||
"go.mau.fi/libsignal/keys/prekey"
|
||||
"go.mau.fi/libsignal/protocol"
|
||||
"go.mau.fi/libsignal/session"
|
||||
"go.mau.fi/libsignal/signalerror"
|
||||
"go.mau.fi/util/random"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
// GenerateMessageID generates a random string that can be used as a message ID on WhatsApp.
|
||||
@ -39,6 +39,9 @@ import (
|
||||
// msgID := cli.GenerateMessageID()
|
||||
// cli.SendMessage(context.Background(), targetJID, &waProto.Message{...}, whatsmeow.SendRequestExtra{ID: msgID})
|
||||
func (cli *Client) GenerateMessageID() types.MessageID {
|
||||
if cli.MessengerConfig != nil {
|
||||
return types.MessageID(strconv.FormatInt(GenerateFacebookMessageID(), 10))
|
||||
}
|
||||
data := make([]byte, 8, 8+20+16)
|
||||
binary.BigEndian.PutUint64(data, uint64(time.Now().Unix()))
|
||||
ownID := cli.getOwnID()
|
||||
@ -46,11 +49,16 @@ func (cli *Client) GenerateMessageID() types.MessageID {
|
||||
data = append(data, []byte(ownID.User)...)
|
||||
data = append(data, []byte("@c.us")...)
|
||||
}
|
||||
data = append(data, randbytes.Make(16)...)
|
||||
data = append(data, random.Bytes(16)...)
|
||||
hash := sha256.Sum256(data)
|
||||
return "3EB0" + strings.ToUpper(hex.EncodeToString(hash[:9]))
|
||||
}
|
||||
|
||||
func GenerateFacebookMessageID() int64 {
|
||||
const randomMask = (1 << 22) - 1
|
||||
return (time.Now().UnixMilli() << 22) | (int64(binary.BigEndian.Uint32(random.Bytes(4))) & randomMask)
|
||||
}
|
||||
|
||||
// GenerateMessageID generates a random string that can be used as a message ID on WhatsApp.
|
||||
//
|
||||
// msgID := whatsmeow.GenerateMessageID()
|
||||
@ -58,7 +66,7 @@ func (cli *Client) GenerateMessageID() types.MessageID {
|
||||
//
|
||||
// Deprecated: WhatsApp web has switched to using a hash of the current timestamp, user id and random bytes. Use Client.GenerateMessageID instead.
|
||||
func GenerateMessageID() types.MessageID {
|
||||
return "3EB0" + strings.ToUpper(hex.EncodeToString(randbytes.Make(8)))
|
||||
return "3EB0" + strings.ToUpper(hex.EncodeToString(random.Bytes(8)))
|
||||
}
|
||||
|
||||
type MessageDebugTimings struct {
|
||||
@ -75,6 +83,24 @@ type MessageDebugTimings struct {
|
||||
Retry time.Duration
|
||||
}
|
||||
|
||||
func (mdt MessageDebugTimings) MarshalZerologObject(evt *zerolog.Event) {
|
||||
evt.Dur("queue", mdt.Queue)
|
||||
evt.Dur("marshal", mdt.Marshal)
|
||||
if mdt.GetParticipants != 0 {
|
||||
evt.Dur("get_participants", mdt.GetParticipants)
|
||||
}
|
||||
evt.Dur("get_devices", mdt.GetDevices)
|
||||
if mdt.GroupEncrypt != 0 {
|
||||
evt.Dur("group_encrypt", mdt.GroupEncrypt)
|
||||
}
|
||||
evt.Dur("peer_encrypt", mdt.PeerEncrypt)
|
||||
evt.Dur("send", mdt.Send)
|
||||
evt.Dur("resp", mdt.Resp)
|
||||
if mdt.Retry != 0 {
|
||||
evt.Dur("retry", mdt.Retry)
|
||||
}
|
||||
}
|
||||
|
||||
type SendResponse struct {
|
||||
// The message timestamp returned by the server
|
||||
Timestamp time.Time
|
||||
@ -82,6 +108,9 @@ type SendResponse struct {
|
||||
// The ID of the sent message
|
||||
ID types.MessageID
|
||||
|
||||
// The server-specified ID of the sent message. Only present for newsletter messages.
|
||||
ServerID types.MessageServerID
|
||||
|
||||
// Message handling duration, used for debugging
|
||||
DebugTimings MessageDebugTimings
|
||||
}
|
||||
@ -102,6 +131,12 @@ type SendRequestExtra struct {
|
||||
ID types.MessageID
|
||||
// Should the message be sent as a peer message (protocol messages to your own devices, e.g. app state key requests)
|
||||
Peer bool
|
||||
// A timeout for the send request. Unlike timeouts using the context parameter, this only applies
|
||||
// to the actual response waiting and not preparing/encrypting the message.
|
||||
// Defaults to 75 seconds. The timeout can be disabled by using a negative value.
|
||||
Timeout time.Duration
|
||||
// When sending media to newsletters, the Handle field returned by the file upload.
|
||||
MediaHandle string
|
||||
}
|
||||
|
||||
// SendMessage sends the given message.
|
||||
@ -136,7 +171,7 @@ func (cli *Client) SendMessage(ctx context.Context, to types.JID, message *waPro
|
||||
} else if len(extra) == 1 {
|
||||
req = extra[0]
|
||||
}
|
||||
if to.AD && !req.Peer {
|
||||
if to.Device > 0 && !req.Peer {
|
||||
err = ErrRecipientADJID
|
||||
return
|
||||
}
|
||||
@ -146,9 +181,20 @@ func (cli *Client) SendMessage(ctx context.Context, to types.JID, message *waPro
|
||||
return
|
||||
}
|
||||
|
||||
if req.Timeout == 0 {
|
||||
req.Timeout = defaultRequestTimeout
|
||||
}
|
||||
if len(req.ID) == 0 {
|
||||
req.ID = cli.GenerateMessageID()
|
||||
}
|
||||
if to.Server == types.NewsletterServer {
|
||||
// TODO somehow deduplicate this with the code in sendNewsletter?
|
||||
if message.EditedMessage != nil {
|
||||
req.ID = types.MessageID(message.GetEditedMessage().GetMessage().GetProtocolMessage().GetKey().GetId())
|
||||
} else if message.ProtocolMessage != nil && message.ProtocolMessage.GetType() == waProto.ProtocolMessage_REVOKE {
|
||||
req.ID = types.MessageID(message.GetProtocolMessage().GetKey().GetId())
|
||||
}
|
||||
}
|
||||
resp.ID = req.ID
|
||||
|
||||
start := time.Now()
|
||||
@ -160,7 +206,7 @@ func (cli *Client) SendMessage(ctx context.Context, to types.JID, message *waPro
|
||||
respChan := cli.waitResponse(req.ID)
|
||||
// Peer message retries aren't implemented yet
|
||||
if !req.Peer {
|
||||
cli.addRecentMessage(to, req.ID, message)
|
||||
cli.addRecentMessage(to, req.ID, message, nil)
|
||||
}
|
||||
if message.GetMessageContextInfo().GetMessageSecret() != nil {
|
||||
err = cli.Store.MsgSecrets.PutMessageSecret(to, ownID, req.ID, message.GetMessageContextInfo().GetMessageSecret())
|
||||
@ -181,6 +227,8 @@ func (cli *Client) SendMessage(ctx context.Context, to types.JID, message *waPro
|
||||
} else {
|
||||
data, err = cli.sendDM(ctx, to, ownID, req.ID, message, &resp.DebugTimings)
|
||||
}
|
||||
case types.NewsletterServer:
|
||||
data, err = cli.sendNewsletter(to, req.ID, message, req.MediaHandle, &resp.DebugTimings)
|
||||
default:
|
||||
err = fmt.Errorf("%w %s", ErrUnknownServer, to.Server)
|
||||
}
|
||||
@ -190,9 +238,20 @@ func (cli *Client) SendMessage(ctx context.Context, to types.JID, message *waPro
|
||||
return
|
||||
}
|
||||
var respNode *waBinary.Node
|
||||
var timeoutChan <-chan time.Time
|
||||
if req.Timeout > 0 {
|
||||
timeoutChan = time.After(req.Timeout)
|
||||
} else {
|
||||
timeoutChan = make(<-chan time.Time)
|
||||
}
|
||||
select {
|
||||
case respNode = <-respChan:
|
||||
case <-timeoutChan:
|
||||
cli.cancelResponse(req.ID, respChan)
|
||||
err = ErrMessageTimedOut
|
||||
return
|
||||
case <-ctx.Done():
|
||||
cli.cancelResponse(req.ID, respChan)
|
||||
err = ctx.Err()
|
||||
return
|
||||
}
|
||||
@ -206,6 +265,7 @@ func (cli *Client) SendMessage(ctx context.Context, to types.JID, message *waPro
|
||||
}
|
||||
}
|
||||
ag := respNode.AttrGetter()
|
||||
resp.ServerID = types.MessageServerID(ag.OptionalInt("server_id"))
|
||||
resp.Timestamp = ag.UnixTime("t")
|
||||
if errorCode := ag.Int("error"); errorCode != 0 {
|
||||
err = fmt.Errorf("%w %d", ErrServerReturnedError, errorCode)
|
||||
@ -241,7 +301,7 @@ func (cli *Client) BuildMessageKey(chat, sender types.JID, id types.MessageID) *
|
||||
}
|
||||
if !sender.IsEmpty() && sender.User != cli.getOwnID().User {
|
||||
key.FromMe = proto.Bool(false)
|
||||
if chat.Server != types.DefaultUserServer {
|
||||
if chat.Server != types.DefaultUserServer && chat.Server != types.MessengerServer {
|
||||
key.Participant = proto.String(sender.ToNonAD().String())
|
||||
}
|
||||
}
|
||||
@ -271,6 +331,8 @@ func (cli *Client) BuildRevoke(chat, sender types.JID, id types.MessageID) *waPr
|
||||
// The built message can be sent normally using Client.SendMessage.
|
||||
//
|
||||
// resp, err := cli.SendMessage(context.Background(), chat, cli.BuildReaction(chat, senderJID, targetMessageID, "🐈️")
|
||||
//
|
||||
// Note that for newsletter messages, you need to use NewsletterSendReaction instead of BuildReaction + SendMessage.
|
||||
func (cli *Client) BuildReaction(chat, sender types.JID, id types.MessageID, reaction string) *waProto.Message {
|
||||
return &waProto.Message{
|
||||
ReactionMessage: &waProto.ReactionMessage{
|
||||
@ -417,7 +479,7 @@ func (cli *Client) SetDisappearingTimer(chat types.JID, timer time.Duration) (er
|
||||
func participantListHashV2(participants []types.JID) string {
|
||||
participantsStrings := make([]string, len(participants))
|
||||
for i, part := range participants {
|
||||
participantsStrings[i] = part.String()
|
||||
participantsStrings[i] = part.ADString()
|
||||
}
|
||||
|
||||
sort.Strings(participantsStrings)
|
||||
@ -425,6 +487,50 @@ func participantListHashV2(participants []types.JID) string {
|
||||
return fmt.Sprintf("2:%s", base64.RawStdEncoding.EncodeToString(hash[:6]))
|
||||
}
|
||||
|
||||
func (cli *Client) sendNewsletter(to types.JID, id types.MessageID, message *waProto.Message, mediaID string, timings *MessageDebugTimings) ([]byte, error) {
|
||||
attrs := waBinary.Attrs{
|
||||
"to": to,
|
||||
"id": id,
|
||||
"type": getTypeFromMessage(message),
|
||||
}
|
||||
if mediaID != "" {
|
||||
attrs["media_id"] = mediaID
|
||||
}
|
||||
if message.EditedMessage != nil {
|
||||
attrs["edit"] = string(types.EditAttributeAdminEdit)
|
||||
message = message.GetEditedMessage().GetMessage().GetProtocolMessage().GetEditedMessage()
|
||||
} else if message.ProtocolMessage != nil && message.ProtocolMessage.GetType() == waProto.ProtocolMessage_REVOKE {
|
||||
attrs["edit"] = string(types.EditAttributeAdminRevoke)
|
||||
message = nil
|
||||
}
|
||||
start := time.Now()
|
||||
plaintext, _, err := marshalMessage(to, message)
|
||||
timings.Marshal = time.Since(start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plaintextNode := waBinary.Node{
|
||||
Tag: "plaintext",
|
||||
Content: plaintext,
|
||||
Attrs: waBinary.Attrs{},
|
||||
}
|
||||
if mediaType := getMediaTypeFromMessage(message); mediaType != "" {
|
||||
plaintextNode.Attrs["mediatype"] = mediaType
|
||||
}
|
||||
node := waBinary.Node{
|
||||
Tag: "message",
|
||||
Attrs: attrs,
|
||||
Content: []waBinary.Node{plaintextNode},
|
||||
}
|
||||
start = time.Now()
|
||||
data, err := cli.sendNodeAndGetData(node)
|
||||
timings.Send = time.Since(start)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send message node: %w", err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (cli *Client) sendGroup(ctx context.Context, to, ownID types.JID, id types.MessageID, message *waProto.Message, timings *MessageDebugTimings) (string, []byte, error) {
|
||||
var participants []types.JID
|
||||
var err error
|
||||
@ -653,16 +759,9 @@ func getButtonAttributes(msg *waProto.Message) waBinary.Attrs {
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
EditAttributeEmpty = ""
|
||||
EditAttributeMessageEdit = "1"
|
||||
EditAttributeSenderRevoke = "7"
|
||||
EditAttributeAdminRevoke = "8"
|
||||
)
|
||||
|
||||
const RemoveReactionText = ""
|
||||
|
||||
func getEditAttribute(msg *waProto.Message) string {
|
||||
func getEditAttribute(msg *waProto.Message) types.EditAttribute {
|
||||
switch {
|
||||
case msg.EditedMessage != nil && msg.EditedMessage.Message != nil:
|
||||
return getEditAttribute(msg.EditedMessage.Message)
|
||||
@ -670,21 +769,21 @@ func getEditAttribute(msg *waProto.Message) string {
|
||||
switch msg.ProtocolMessage.GetType() {
|
||||
case waProto.ProtocolMessage_REVOKE:
|
||||
if msg.ProtocolMessage.GetKey().GetFromMe() {
|
||||
return EditAttributeSenderRevoke
|
||||
return types.EditAttributeSenderRevoke
|
||||
} else {
|
||||
return EditAttributeAdminRevoke
|
||||
return types.EditAttributeAdminRevoke
|
||||
}
|
||||
case waProto.ProtocolMessage_MESSAGE_EDIT:
|
||||
if msg.ProtocolMessage.EditedMessage != nil {
|
||||
return EditAttributeMessageEdit
|
||||
return types.EditAttributeMessageEdit
|
||||
}
|
||||
}
|
||||
case msg.ReactionMessage != nil && msg.ReactionMessage.GetText() == RemoveReactionText:
|
||||
return EditAttributeSenderRevoke
|
||||
return types.EditAttributeSenderRevoke
|
||||
case msg.KeepInChatMessage != nil && msg.KeepInChatMessage.GetKey().GetFromMe() && msg.KeepInChatMessage.GetKeepType() == waProto.KeepType_UNDO_KEEP_FOR_ALL:
|
||||
return EditAttributeSenderRevoke
|
||||
return types.EditAttributeSenderRevoke
|
||||
}
|
||||
return EditAttributeEmpty
|
||||
return types.EditAttributeEmpty
|
||||
}
|
||||
|
||||
func (cli *Client) preparePeerMessageNode(to types.JID, id types.MessageID, message *waProto.Message, timings *MessageDebugTimings) (*waBinary.Node, error) {
|
||||
@ -711,7 +810,7 @@ func (cli *Client) preparePeerMessageNode(to types.JID, id types.MessageID, mess
|
||||
return nil, fmt.Errorf("failed to encrypt peer message for %s: %v", to, err)
|
||||
}
|
||||
content := []waBinary.Node{*encrypted}
|
||||
if isPreKey {
|
||||
if isPreKey && cli.MessengerConfig == nil {
|
||||
content = append(content, cli.makeDeviceIdentityNode())
|
||||
}
|
||||
return &waBinary.Node{
|
||||
@ -770,10 +869,10 @@ func (cli *Client) prepareMessageNode(ctx context.Context, to, ownID types.JID,
|
||||
"to": to,
|
||||
}
|
||||
if editAttr := getEditAttribute(message); editAttr != "" {
|
||||
attrs["edit"] = editAttr
|
||||
attrs["edit"] = string(editAttr)
|
||||
encAttrs["decrypt-fail"] = string(events.DecryptFailHide)
|
||||
}
|
||||
if msgType == "reaction" {
|
||||
if msgType == "reaction" || message.GetPollUpdateMessage() != nil {
|
||||
encAttrs["decrypt-fail"] = string(events.DecryptFailHide)
|
||||
}
|
||||
|
||||
@ -792,13 +891,16 @@ func (cli *Client) prepareMessageNode(ctx context.Context, to, ownID types.JID,
|
||||
}
|
||||
|
||||
func marshalMessage(to types.JID, message *waProto.Message) (plaintext, dsmPlaintext []byte, err error) {
|
||||
if message == nil && to.Server == types.NewsletterServer {
|
||||
return
|
||||
}
|
||||
plaintext, err = proto.Marshal(message)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to marshal message: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
if to.Server != types.GroupServer {
|
||||
if to.Server != types.GroupServer && to.Server != types.NewsletterServer {
|
||||
dsmPlaintext, err = proto.Marshal(&waProto.Message{
|
||||
DeviceSentMessage: &waProto.DeviceSentMessage{
|
||||
DestinationJid: proto.String(to.String()),
|
||||
@ -929,9 +1031,10 @@ func (cli *Client) encryptMessageForDevice(plaintext []byte, to types.JID, bundl
|
||||
}
|
||||
copyAttrs(extraAttrs, encAttrs)
|
||||
|
||||
includeDeviceIdentity := encAttrs["type"] == "pkmsg" && cli.MessengerConfig == nil
|
||||
return &waBinary.Node{
|
||||
Tag: "enc",
|
||||
Attrs: encAttrs,
|
||||
Content: ciphertext.Serialize(),
|
||||
}, encAttrs["type"] == "pkmsg", nil
|
||||
}, includeDeviceIdentity, nil
|
||||
}
|
||||
|
606
vendor/go.mau.fi/whatsmeow/sendfb.go
vendored
Normal file
606
vendor/go.mau.fi/whatsmeow/sendfb.go
vendored
Normal file
@ -0,0 +1,606 @@
|
||||
// Copyright (c) 2024 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 (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.mau.fi/libsignal/groups"
|
||||
"go.mau.fi/libsignal/keys/prekey"
|
||||
"go.mau.fi/libsignal/protocol"
|
||||
"go.mau.fi/libsignal/session"
|
||||
"go.mau.fi/libsignal/signalerror"
|
||||
"go.mau.fi/util/random"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waCommon"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waConsumerApplication"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMsgApplication"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMsgTransport"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/types/events"
|
||||
)
|
||||
|
||||
const FBMessageVersion = 3
|
||||
const FBMessageApplicationVersion = 2
|
||||
const FBConsumerMessageVersion = 1
|
||||
|
||||
// SendFBMessage sends the given v3 message to the given JID.
|
||||
func (cli *Client) SendFBMessage(
|
||||
ctx context.Context,
|
||||
to types.JID,
|
||||
message *waConsumerApplication.ConsumerApplication,
|
||||
metadata *waMsgApplication.MessageApplication_Metadata,
|
||||
extra ...SendRequestExtra,
|
||||
) (resp SendResponse, err error) {
|
||||
var req SendRequestExtra
|
||||
if len(extra) > 1 {
|
||||
err = errors.New("only one extra parameter may be provided to SendMessage")
|
||||
return
|
||||
} else if len(extra) == 1 {
|
||||
req = extra[0]
|
||||
}
|
||||
consumerMessage, err := proto.Marshal(message)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to marshal consumer message: %w", err)
|
||||
return
|
||||
}
|
||||
if metadata == nil {
|
||||
metadata = &waMsgApplication.MessageApplication_Metadata{}
|
||||
}
|
||||
metadata.FrankingVersion = 0
|
||||
metadata.FrankingKey = random.Bytes(32)
|
||||
msgAttrs := getAttrsFromFBMessage(message)
|
||||
messageAppProto := &waMsgApplication.MessageApplication{
|
||||
Payload: &waMsgApplication.MessageApplication_Payload{
|
||||
Content: &waMsgApplication.MessageApplication_Payload_SubProtocol{
|
||||
SubProtocol: &waMsgApplication.MessageApplication_SubProtocolPayload{
|
||||
SubProtocol: &waMsgApplication.MessageApplication_SubProtocolPayload_ConsumerMessage{
|
||||
ConsumerMessage: &waCommon.SubProtocol{
|
||||
Payload: consumerMessage,
|
||||
Version: FBConsumerMessageVersion,
|
||||
},
|
||||
},
|
||||
FutureProof: waCommon.FutureProofBehavior_PLACEHOLDER,
|
||||
},
|
||||
},
|
||||
},
|
||||
Metadata: metadata,
|
||||
}
|
||||
messageApp, err := proto.Marshal(messageAppProto)
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("failed to marshal message application: %w", err)
|
||||
}
|
||||
frankingHash := hmac.New(sha256.New, metadata.FrankingKey)
|
||||
frankingHash.Write(messageApp)
|
||||
frankingTag := frankingHash.Sum(nil)
|
||||
if to.Device > 0 && !req.Peer {
|
||||
err = ErrRecipientADJID
|
||||
return
|
||||
}
|
||||
ownID := cli.getOwnID()
|
||||
if ownID.IsEmpty() {
|
||||
err = ErrNotLoggedIn
|
||||
return
|
||||
}
|
||||
|
||||
if req.Timeout == 0 {
|
||||
req.Timeout = defaultRequestTimeout
|
||||
}
|
||||
if len(req.ID) == 0 {
|
||||
req.ID = cli.GenerateMessageID()
|
||||
}
|
||||
resp.ID = req.ID
|
||||
|
||||
start := time.Now()
|
||||
// Sending multiple messages at a time can cause weird issues and makes it harder to retry safely
|
||||
cli.messageSendLock.Lock()
|
||||
resp.DebugTimings.Queue = time.Since(start)
|
||||
defer cli.messageSendLock.Unlock()
|
||||
|
||||
respChan := cli.waitResponse(req.ID)
|
||||
if !req.Peer {
|
||||
cli.addRecentMessage(to, req.ID, nil, messageAppProto)
|
||||
}
|
||||
var phash string
|
||||
var data []byte
|
||||
switch to.Server {
|
||||
case types.GroupServer:
|
||||
phash, data, err = cli.sendGroupV3(ctx, to, ownID, req.ID, messageApp, msgAttrs, frankingTag, &resp.DebugTimings)
|
||||
case types.DefaultUserServer, types.MessengerServer:
|
||||
if req.Peer {
|
||||
err = fmt.Errorf("peer messages to fb are not yet supported")
|
||||
//data, err = cli.sendPeerMessage(to, req.ID, message, &resp.DebugTimings)
|
||||
} else {
|
||||
data, phash, err = cli.sendDMV3(ctx, to, ownID, req.ID, messageApp, msgAttrs, frankingTag, &resp.DebugTimings)
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("%w %s", ErrUnknownServer, to.Server)
|
||||
}
|
||||
start = time.Now()
|
||||
if err != nil {
|
||||
cli.cancelResponse(req.ID, respChan)
|
||||
return
|
||||
}
|
||||
var respNode *waBinary.Node
|
||||
var timeoutChan <-chan time.Time
|
||||
if req.Timeout > 0 {
|
||||
timeoutChan = time.After(req.Timeout)
|
||||
} else {
|
||||
timeoutChan = make(<-chan time.Time)
|
||||
}
|
||||
select {
|
||||
case respNode = <-respChan:
|
||||
case <-timeoutChan:
|
||||
cli.cancelResponse(req.ID, respChan)
|
||||
err = ErrMessageTimedOut
|
||||
return
|
||||
case <-ctx.Done():
|
||||
cli.cancelResponse(req.ID, respChan)
|
||||
err = ctx.Err()
|
||||
return
|
||||
}
|
||||
resp.DebugTimings.Resp = time.Since(start)
|
||||
if isDisconnectNode(respNode) {
|
||||
start = time.Now()
|
||||
respNode, err = cli.retryFrame("message send", req.ID, data, respNode, ctx, 0)
|
||||
resp.DebugTimings.Retry = time.Since(start)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
ag := respNode.AttrGetter()
|
||||
resp.ServerID = types.MessageServerID(ag.OptionalInt("server_id"))
|
||||
resp.Timestamp = ag.UnixTime("t")
|
||||
if errorCode := ag.Int("error"); errorCode != 0 {
|
||||
err = fmt.Errorf("%w %d", ErrServerReturnedError, errorCode)
|
||||
}
|
||||
expectedPHash := ag.OptionalString("phash")
|
||||
if len(expectedPHash) > 0 && phash != expectedPHash {
|
||||
cli.Log.Warnf("Server returned different participant list hash when sending to %s. Some devices may not have received the message.", to)
|
||||
// TODO also invalidate device list caches
|
||||
cli.groupParticipantsCacheLock.Lock()
|
||||
delete(cli.groupParticipantsCache, to)
|
||||
cli.groupParticipantsCacheLock.Unlock()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) sendGroupV3(
|
||||
ctx context.Context,
|
||||
to,
|
||||
ownID types.JID,
|
||||
id types.MessageID,
|
||||
messageApp []byte,
|
||||
msgAttrs messageAttrs,
|
||||
frankingTag []byte,
|
||||
timings *MessageDebugTimings,
|
||||
) (string, []byte, error) {
|
||||
var participants []types.JID
|
||||
var err error
|
||||
start := time.Now()
|
||||
if to.Server == types.GroupServer {
|
||||
participants, err = cli.getGroupMembers(ctx, to)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to get group members: %w", err)
|
||||
}
|
||||
}
|
||||
timings.GetParticipants = time.Since(start)
|
||||
|
||||
start = time.Now()
|
||||
builder := groups.NewGroupSessionBuilder(cli.Store, pbSerializer)
|
||||
senderKeyName := protocol.NewSenderKeyName(to.String(), ownID.SignalAddress())
|
||||
signalSKDMessage, err := builder.Create(senderKeyName)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to create sender key distribution message to send %s to %s: %w", id, to, err)
|
||||
}
|
||||
skdm := &waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage{
|
||||
GroupID: to.String(),
|
||||
AxolotlSenderKeyDistributionMessage: signalSKDMessage.Serialize(),
|
||||
}
|
||||
|
||||
cipher := groups.NewGroupCipher(builder, senderKeyName, cli.Store)
|
||||
plaintext, err := proto.Marshal(&waMsgTransport.MessageTransport{
|
||||
Payload: &waMsgTransport.MessageTransport_Payload{
|
||||
ApplicationPayload: &waCommon.SubProtocol{
|
||||
Payload: messageApp,
|
||||
Version: FBMessageApplicationVersion,
|
||||
},
|
||||
FutureProof: waCommon.FutureProofBehavior_PLACEHOLDER,
|
||||
},
|
||||
Protocol: &waMsgTransport.MessageTransport_Protocol{
|
||||
Integral: &waMsgTransport.MessageTransport_Protocol_Integral{
|
||||
Padding: padMessage(nil),
|
||||
DSM: nil,
|
||||
},
|
||||
Ancillary: &waMsgTransport.MessageTransport_Protocol_Ancillary{
|
||||
Skdm: nil,
|
||||
DeviceListMetadata: nil,
|
||||
Icdc: nil,
|
||||
BackupDirective: &waMsgTransport.MessageTransport_Protocol_Ancillary_BackupDirective{
|
||||
MessageID: id,
|
||||
ActionType: waMsgTransport.MessageTransport_Protocol_Ancillary_BackupDirective_UPSERT,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to marshal message transport: %w", err)
|
||||
}
|
||||
encrypted, err := cipher.Encrypt(plaintext)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to encrypt group message to send %s to %s: %w", id, to, err)
|
||||
}
|
||||
ciphertext := encrypted.SignedSerialize()
|
||||
timings.GroupEncrypt = time.Since(start)
|
||||
|
||||
node, allDevices, err := cli.prepareMessageNodeV3(ctx, to, ownID, id, nil, skdm, msgAttrs, frankingTag, participants, timings)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
phash := participantListHashV2(allDevices)
|
||||
node.Attrs["phash"] = phash
|
||||
skMsg := waBinary.Node{
|
||||
Tag: "enc",
|
||||
Content: ciphertext,
|
||||
Attrs: waBinary.Attrs{"v": "3", "type": "skmsg"},
|
||||
}
|
||||
if msgAttrs.MediaType != "" {
|
||||
skMsg.Attrs["mediatype"] = msgAttrs.MediaType
|
||||
}
|
||||
node.Content = append(node.GetChildren(), skMsg)
|
||||
|
||||
start = time.Now()
|
||||
data, err := cli.sendNodeAndGetData(*node)
|
||||
timings.Send = time.Since(start)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to send message node: %w", err)
|
||||
}
|
||||
return phash, data, nil
|
||||
}
|
||||
|
||||
func (cli *Client) sendDMV3(
|
||||
ctx context.Context,
|
||||
to,
|
||||
ownID types.JID,
|
||||
id types.MessageID,
|
||||
messageApp []byte,
|
||||
msgAttrs messageAttrs,
|
||||
frankingTag []byte,
|
||||
timings *MessageDebugTimings,
|
||||
) ([]byte, string, error) {
|
||||
payload := &waMsgTransport.MessageTransport_Payload{
|
||||
ApplicationPayload: &waCommon.SubProtocol{
|
||||
Payload: messageApp,
|
||||
Version: FBMessageApplicationVersion,
|
||||
},
|
||||
FutureProof: waCommon.FutureProofBehavior_PLACEHOLDER,
|
||||
}
|
||||
|
||||
node, allDevices, err := cli.prepareMessageNodeV3(ctx, to, ownID, id, payload, nil, msgAttrs, frankingTag, []types.JID{to, ownID.ToNonAD()}, timings)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
start := time.Now()
|
||||
data, err := cli.sendNodeAndGetData(*node)
|
||||
timings.Send = time.Since(start)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to send message node: %w", err)
|
||||
}
|
||||
return data, participantListHashV2(allDevices), nil
|
||||
}
|
||||
|
||||
type messageAttrs struct {
|
||||
Type string
|
||||
MediaType string
|
||||
Edit types.EditAttribute
|
||||
DecryptFail events.DecryptFailMode
|
||||
PollType string
|
||||
}
|
||||
|
||||
func getAttrsFromFBMessage(msg *waConsumerApplication.ConsumerApplication) (attrs messageAttrs) {
|
||||
switch payload := msg.GetPayload().GetPayload().(type) {
|
||||
case *waConsumerApplication.ConsumerApplication_Payload_Content:
|
||||
switch content := payload.Content.GetContent().(type) {
|
||||
case *waConsumerApplication.ConsumerApplication_Content_MessageText,
|
||||
*waConsumerApplication.ConsumerApplication_Content_ExtendedTextMessage:
|
||||
attrs.Type = "text"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_ImageMessage:
|
||||
attrs.MediaType = "image"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_StickerMessage:
|
||||
attrs.MediaType = "sticker"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_ViewOnceMessage:
|
||||
switch content.ViewOnceMessage.GetViewOnceContent().(type) {
|
||||
case *waConsumerApplication.ConsumerApplication_ViewOnceMessage_ImageMessage:
|
||||
attrs.MediaType = "image"
|
||||
case *waConsumerApplication.ConsumerApplication_ViewOnceMessage_VideoMessage:
|
||||
attrs.MediaType = "video"
|
||||
}
|
||||
case *waConsumerApplication.ConsumerApplication_Content_DocumentMessage:
|
||||
attrs.MediaType = "document"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_AudioMessage:
|
||||
if content.AudioMessage.GetPTT() {
|
||||
attrs.MediaType = "ptt"
|
||||
} else {
|
||||
attrs.MediaType = "audio"
|
||||
}
|
||||
case *waConsumerApplication.ConsumerApplication_Content_VideoMessage:
|
||||
// TODO gifPlayback?
|
||||
attrs.MediaType = "video"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_LocationMessage:
|
||||
attrs.MediaType = "location"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_LiveLocationMessage:
|
||||
attrs.MediaType = "location"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_ContactMessage:
|
||||
attrs.MediaType = "vcard"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_ContactsArrayMessage:
|
||||
attrs.MediaType = "contact_array"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_PollCreationMessage:
|
||||
attrs.PollType = "creation"
|
||||
attrs.Type = "poll"
|
||||
case *waConsumerApplication.ConsumerApplication_Content_PollUpdateMessage:
|
||||
attrs.PollType = "vote"
|
||||
attrs.Type = "poll"
|
||||
attrs.DecryptFail = events.DecryptFailHide
|
||||
case *waConsumerApplication.ConsumerApplication_Content_ReactionMessage:
|
||||
attrs.Type = "reaction"
|
||||
attrs.DecryptFail = events.DecryptFailHide
|
||||
case *waConsumerApplication.ConsumerApplication_Content_EditMessage:
|
||||
attrs.Edit = types.EditAttributeMessageEdit
|
||||
attrs.DecryptFail = events.DecryptFailHide
|
||||
}
|
||||
if attrs.MediaType != "" && attrs.Type == "" {
|
||||
attrs.Type = "media"
|
||||
}
|
||||
case *waConsumerApplication.ConsumerApplication_Payload_ApplicationData:
|
||||
switch content := payload.ApplicationData.GetApplicationContent().(type) {
|
||||
case *waConsumerApplication.ConsumerApplication_ApplicationData_Revoke:
|
||||
if content.Revoke.GetKey().GetFromMe() {
|
||||
attrs.Edit = types.EditAttributeSenderRevoke
|
||||
} else {
|
||||
attrs.Edit = types.EditAttributeAdminRevoke
|
||||
}
|
||||
attrs.DecryptFail = events.DecryptFailHide
|
||||
}
|
||||
case *waConsumerApplication.ConsumerApplication_Payload_Signal:
|
||||
case *waConsumerApplication.ConsumerApplication_Payload_SubProtocol:
|
||||
}
|
||||
if attrs.Type == "" {
|
||||
attrs.Type = "text"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) prepareMessageNodeV3(
|
||||
ctx context.Context,
|
||||
to,
|
||||
ownID types.JID,
|
||||
id types.MessageID,
|
||||
payload *waMsgTransport.MessageTransport_Payload,
|
||||
skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage,
|
||||
msgAttrs messageAttrs,
|
||||
frankingTag []byte,
|
||||
participants []types.JID,
|
||||
timings *MessageDebugTimings,
|
||||
) (*waBinary.Node, []types.JID, error) {
|
||||
start := time.Now()
|
||||
allDevices, err := cli.GetUserDevicesContext(ctx, participants)
|
||||
timings.GetDevices = time.Since(start)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get device list: %w", err)
|
||||
}
|
||||
|
||||
encAttrs := waBinary.Attrs{}
|
||||
attrs := waBinary.Attrs{
|
||||
"id": id,
|
||||
"type": msgAttrs.Type,
|
||||
"to": to,
|
||||
}
|
||||
// Only include mediatype on DMs, for groups it's in the skmsg node
|
||||
if payload != nil && msgAttrs.MediaType != "" {
|
||||
encAttrs["mediatype"] = msgAttrs.MediaType
|
||||
}
|
||||
if msgAttrs.Edit != "" {
|
||||
attrs["edit"] = string(msgAttrs.Edit)
|
||||
}
|
||||
if msgAttrs.DecryptFail != "" {
|
||||
encAttrs["decrypt-fail"] = string(msgAttrs.DecryptFail)
|
||||
}
|
||||
|
||||
dsm := &waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage{
|
||||
DestinationJID: to.String(),
|
||||
Phash: "",
|
||||
}
|
||||
|
||||
start = time.Now()
|
||||
participantNodes := cli.encryptMessageForDevicesV3(ctx, allDevices, ownID, id, payload, skdm, dsm, encAttrs)
|
||||
timings.PeerEncrypt = time.Since(start)
|
||||
content := make([]waBinary.Node, 0, 4)
|
||||
content = append(content, waBinary.Node{
|
||||
Tag: "participants",
|
||||
Content: participantNodes,
|
||||
})
|
||||
metaAttrs := make(waBinary.Attrs)
|
||||
if msgAttrs.PollType != "" {
|
||||
metaAttrs["polltype"] = msgAttrs.PollType
|
||||
}
|
||||
if msgAttrs.DecryptFail != "" {
|
||||
metaAttrs["decrypt-fail"] = string(msgAttrs.DecryptFail)
|
||||
}
|
||||
if len(metaAttrs) > 0 {
|
||||
content = append(content, waBinary.Node{
|
||||
Tag: "meta",
|
||||
Attrs: metaAttrs,
|
||||
})
|
||||
}
|
||||
traceRequestID := uuid.New()
|
||||
content = append(content, waBinary.Node{
|
||||
Tag: "franking",
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "franking_tag",
|
||||
Content: frankingTag,
|
||||
}},
|
||||
}, waBinary.Node{
|
||||
Tag: "trace",
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "request_id",
|
||||
Content: traceRequestID[:],
|
||||
}},
|
||||
})
|
||||
return &waBinary.Node{
|
||||
Tag: "message",
|
||||
Attrs: attrs,
|
||||
Content: content,
|
||||
}, allDevices, nil
|
||||
}
|
||||
|
||||
func (cli *Client) encryptMessageForDevicesV3(
|
||||
ctx context.Context,
|
||||
allDevices []types.JID,
|
||||
ownID types.JID,
|
||||
id string,
|
||||
payload *waMsgTransport.MessageTransport_Payload,
|
||||
skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage,
|
||||
dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage,
|
||||
encAttrs waBinary.Attrs,
|
||||
) []waBinary.Node {
|
||||
participantNodes := make([]waBinary.Node, 0, len(allDevices))
|
||||
var retryDevices []types.JID
|
||||
for _, jid := range allDevices {
|
||||
var dsmForDevice *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage
|
||||
if jid.User == ownID.User {
|
||||
if jid == ownID {
|
||||
continue
|
||||
}
|
||||
dsmForDevice = dsm
|
||||
}
|
||||
encrypted, err := cli.encryptMessageForDeviceAndWrapV3(payload, skdm, dsmForDevice, jid, nil, encAttrs)
|
||||
if errors.Is(err, ErrNoSession) {
|
||||
retryDevices = append(retryDevices, jid)
|
||||
continue
|
||||
} else if err != nil {
|
||||
cli.Log.Warnf("Failed to encrypt %s for %s: %v", id, jid, err)
|
||||
continue
|
||||
}
|
||||
participantNodes = append(participantNodes, *encrypted)
|
||||
}
|
||||
if len(retryDevices) > 0 {
|
||||
bundles, err := cli.fetchPreKeys(ctx, retryDevices)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Failed to fetch prekeys for %v to retry encryption: %v", retryDevices, err)
|
||||
} else {
|
||||
for _, jid := range retryDevices {
|
||||
resp := bundles[jid]
|
||||
if resp.err != nil {
|
||||
cli.Log.Warnf("Failed to fetch prekey for %s: %v", jid, resp.err)
|
||||
continue
|
||||
}
|
||||
var dsmForDevice *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage
|
||||
if jid.User == ownID.User {
|
||||
dsmForDevice = dsm
|
||||
}
|
||||
encrypted, err := cli.encryptMessageForDeviceAndWrapV3(payload, skdm, dsmForDevice, jid, resp.bundle, encAttrs)
|
||||
if err != nil {
|
||||
cli.Log.Warnf("Failed to encrypt %s for %s (retry): %v", id, jid, err)
|
||||
continue
|
||||
}
|
||||
participantNodes = append(participantNodes, *encrypted)
|
||||
}
|
||||
}
|
||||
}
|
||||
return participantNodes
|
||||
}
|
||||
|
||||
func (cli *Client) encryptMessageForDeviceAndWrapV3(
|
||||
payload *waMsgTransport.MessageTransport_Payload,
|
||||
skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage,
|
||||
dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage,
|
||||
to types.JID,
|
||||
bundle *prekey.Bundle,
|
||||
encAttrs waBinary.Attrs,
|
||||
) (*waBinary.Node, error) {
|
||||
node, err := cli.encryptMessageForDeviceV3(payload, skdm, dsm, to, bundle, encAttrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &waBinary.Node{
|
||||
Tag: "to",
|
||||
Attrs: waBinary.Attrs{"jid": to},
|
||||
Content: []waBinary.Node{*node},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cli *Client) encryptMessageForDeviceV3(
|
||||
payload *waMsgTransport.MessageTransport_Payload,
|
||||
skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage,
|
||||
dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage,
|
||||
to types.JID,
|
||||
bundle *prekey.Bundle,
|
||||
extraAttrs waBinary.Attrs,
|
||||
) (*waBinary.Node, error) {
|
||||
builder := session.NewBuilderFromSignal(cli.Store, to.SignalAddress(), pbSerializer)
|
||||
if bundle != nil {
|
||||
cli.Log.Debugf("Processing prekey bundle for %s", to)
|
||||
err := builder.ProcessBundle(bundle)
|
||||
if cli.AutoTrustIdentity && errors.Is(err, signalerror.ErrUntrustedIdentity) {
|
||||
cli.Log.Warnf("Got %v error while trying to process prekey bundle for %s, clearing stored identity and retrying", err, to)
|
||||
cli.clearUntrustedIdentity(to)
|
||||
err = builder.ProcessBundle(bundle)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to process prekey bundle: %w", err)
|
||||
}
|
||||
} else if !cli.Store.ContainsSession(to.SignalAddress()) {
|
||||
return nil, ErrNoSession
|
||||
}
|
||||
cipher := session.NewCipher(builder, to.SignalAddress())
|
||||
plaintext, err := proto.Marshal(&waMsgTransport.MessageTransport{
|
||||
Payload: payload,
|
||||
Protocol: &waMsgTransport.MessageTransport_Protocol{
|
||||
Integral: &waMsgTransport.MessageTransport_Protocol_Integral{
|
||||
Padding: padMessage(nil),
|
||||
DSM: dsm,
|
||||
},
|
||||
Ancillary: &waMsgTransport.MessageTransport_Protocol_Ancillary{
|
||||
Skdm: skdm,
|
||||
DeviceListMetadata: nil,
|
||||
Icdc: nil,
|
||||
BackupDirective: nil,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal message transport: %w", err)
|
||||
}
|
||||
ciphertext, err := cipher.Encrypt(plaintext)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cipher encryption failed: %w", err)
|
||||
}
|
||||
|
||||
encAttrs := waBinary.Attrs{
|
||||
"v": FBMessageVersion,
|
||||
"type": "msg",
|
||||
}
|
||||
if ciphertext.Type() == protocol.PREKEY_TYPE {
|
||||
encAttrs["type"] = "pkmsg"
|
||||
}
|
||||
copyAttrs(extraAttrs, encAttrs)
|
||||
|
||||
return &waBinary.Node{
|
||||
Tag: "enc",
|
||||
Attrs: encAttrs,
|
||||
Content: ciphertext.Serialize(),
|
||||
}, nil
|
||||
}
|
@ -26,7 +26,7 @@ const (
|
||||
const (
|
||||
NoiseStartPattern = "Noise_XX_25519_AESGCM_SHA256\x00\x00\x00\x00"
|
||||
|
||||
WAMagicValue = 5
|
||||
WAMagicValue = 6
|
||||
)
|
||||
|
||||
var WAConnHeader = []byte{'W', 'A', WAMagicValue, token.DictVersion}
|
||||
|
25
vendor/go.mau.fi/whatsmeow/socket/framesocket.go
vendored
25
vendor/go.mau.fi/whatsmeow/socket/framesocket.go
vendored
@ -11,7 +11,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -20,8 +19,6 @@ import (
|
||||
waLog "go.mau.fi/whatsmeow/util/log"
|
||||
)
|
||||
|
||||
type Proxy = func(*http.Request) (*url.URL, error)
|
||||
|
||||
type FrameSocket struct {
|
||||
conn *websocket.Conn
|
||||
ctx context.Context
|
||||
@ -29,12 +26,15 @@ type FrameSocket struct {
|
||||
log waLog.Logger
|
||||
lock sync.Mutex
|
||||
|
||||
URL string
|
||||
HTTPHeaders http.Header
|
||||
|
||||
Frames chan []byte
|
||||
OnDisconnect func(remote bool)
|
||||
WriteTimeout time.Duration
|
||||
|
||||
Header []byte
|
||||
Proxy Proxy
|
||||
Dialer websocket.Dialer
|
||||
|
||||
incomingLength int
|
||||
receivedLength int
|
||||
@ -42,14 +42,17 @@ type FrameSocket struct {
|
||||
partialHeader []byte
|
||||
}
|
||||
|
||||
func NewFrameSocket(log waLog.Logger, header []byte, proxy Proxy) *FrameSocket {
|
||||
func NewFrameSocket(log waLog.Logger, dialer websocket.Dialer) *FrameSocket {
|
||||
return &FrameSocket{
|
||||
conn: nil,
|
||||
log: log,
|
||||
Header: header,
|
||||
Header: WAConnHeader,
|
||||
Frames: make(chan []byte),
|
||||
|
||||
Proxy: proxy,
|
||||
URL: URL,
|
||||
HTTPHeaders: http.Header{"Origin": {Origin}},
|
||||
|
||||
Dialer: dialer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,13 +101,9 @@ func (fs *FrameSocket) Connect() error {
|
||||
return ErrSocketAlreadyOpen
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
dialer := websocket.Dialer{
|
||||
Proxy: fs.Proxy,
|
||||
}
|
||||
|
||||
headers := http.Header{"Origin": []string{Origin}}
|
||||
fs.log.Debugf("Dialing %s", URL)
|
||||
conn, _, err := dialer.Dial(URL, headers)
|
||||
fs.log.Debugf("Dialing %s", fs.URL)
|
||||
conn, _, err := fs.Dialer.Dial(fs.URL, fs.HTTPHeaders)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return fmt.Errorf("couldn't dial whatsapp web websocket: %w", err)
|
||||
|
@ -24,7 +24,7 @@ type NoiseSocket struct {
|
||||
writeCounter uint32
|
||||
readCounter uint32
|
||||
writeLock sync.Mutex
|
||||
destroyed uint32
|
||||
destroyed atomic.Bool
|
||||
stopConsumer chan struct{}
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ func (ns *NoiseSocket) Context() context.Context {
|
||||
}
|
||||
|
||||
func (ns *NoiseSocket) Stop(disconnect bool) {
|
||||
if atomic.CompareAndSwapUint32(&ns.destroyed, 0, 1) {
|
||||
if ns.destroyed.CompareAndSwap(false, true) {
|
||||
close(ns.stopConsumer)
|
||||
ns.fs.OnDisconnect = nil
|
||||
if disconnect {
|
||||
|
@ -74,7 +74,7 @@ func (vc WAVersionContainer) ProtoAppVersion() *waProto.ClientPayload_UserAgent_
|
||||
}
|
||||
|
||||
// waVersion is the WhatsApp web client version
|
||||
var waVersion = WAVersionContainer{2, 2332, 15}
|
||||
var waVersion = WAVersionContainer{2, 2412, 50}
|
||||
|
||||
// waVersionHash is the md5 hash of a dot-separated waVersion
|
||||
var waVersionHash [16]byte
|
||||
|
@ -12,12 +12,14 @@ import (
|
||||
"fmt"
|
||||
mathRand "math/rand"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.mau.fi/util/random"
|
||||
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/store"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/util/keys"
|
||||
waLog "go.mau.fi/whatsmeow/util/log"
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
// Container is a wrapper for a SQL database that can contain multiple whatsmeow sessions.
|
||||
@ -86,7 +88,7 @@ const getAllDevicesQuery = `
|
||||
SELECT jid, registration_id, noise_key, identity_key,
|
||||
signed_pre_key, signed_pre_key_id, signed_pre_key_sig,
|
||||
adv_key, adv_details, adv_account_sig, adv_account_sig_key, adv_device_sig,
|
||||
platform, business_name, push_name
|
||||
platform, business_name, push_name, facebook_uuid
|
||||
FROM whatsmeow_device
|
||||
`
|
||||
|
||||
@ -103,12 +105,13 @@ func (c *Container) scanDevice(row scannable) (*store.Device, error) {
|
||||
device.SignedPreKey = &keys.PreKey{}
|
||||
var noisePriv, identityPriv, preKeyPriv, preKeySig []byte
|
||||
var account waProto.ADVSignedDeviceIdentity
|
||||
var fbUUID uuid.NullUUID
|
||||
|
||||
err := row.Scan(
|
||||
&device.ID, &device.RegistrationID, &noisePriv, &identityPriv,
|
||||
&preKeyPriv, &device.SignedPreKey.KeyID, &preKeySig,
|
||||
&device.AdvSecretKey, &account.Details, &account.AccountSignature, &account.AccountSignatureKey, &account.DeviceSignature,
|
||||
&device.Platform, &device.BusinessName, &device.PushName)
|
||||
&device.Platform, &device.BusinessName, &device.PushName, &fbUUID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan session: %w", err)
|
||||
} else if len(noisePriv) != 32 || len(identityPriv) != 32 || len(preKeyPriv) != 32 || len(preKeySig) != 64 {
|
||||
@ -120,6 +123,7 @@ func (c *Container) scanDevice(row scannable) (*store.Device, error) {
|
||||
device.SignedPreKey.KeyPair = *keys.NewKeyPairFromPrivateKey(*(*[32]byte)(preKeyPriv))
|
||||
device.SignedPreKey.Signature = (*[64]byte)(preKeySig)
|
||||
device.Account = &account
|
||||
device.FacebookUUID = fbUUID.UUID
|
||||
|
||||
innerStore := NewSQLStore(c, *device.ID)
|
||||
device.Identities = innerStore
|
||||
@ -188,8 +192,8 @@ const (
|
||||
INSERT INTO whatsmeow_device (jid, registration_id, noise_key, identity_key,
|
||||
signed_pre_key, signed_pre_key_id, signed_pre_key_sig,
|
||||
adv_key, adv_details, adv_account_sig, adv_account_sig_key, adv_device_sig,
|
||||
platform, business_name, push_name)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
||||
platform, business_name, push_name, facebook_uuid)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||||
ON CONFLICT (jid) DO UPDATE
|
||||
SET platform=excluded.platform, business_name=excluded.business_name, push_name=excluded.push_name
|
||||
`
|
||||
@ -210,7 +214,7 @@ func (c *Container) NewDevice() *store.Device {
|
||||
NoiseKey: keys.NewKeyPair(),
|
||||
IdentityKey: keys.NewKeyPair(),
|
||||
RegistrationID: mathRand.Uint32(),
|
||||
AdvSecretKey: randbytes.Make(32),
|
||||
AdvSecretKey: random.Bytes(32),
|
||||
}
|
||||
device.SignedPreKey = device.IdentityKey.CreateSignedPreKey(1)
|
||||
return device
|
||||
@ -219,6 +223,14 @@ func (c *Container) NewDevice() *store.Device {
|
||||
// ErrDeviceIDMustBeSet is the error returned by PutDevice if you try to save a device before knowing its JID.
|
||||
var ErrDeviceIDMustBeSet = errors.New("device JID must be known before accessing database")
|
||||
|
||||
// Close will close the container's database
|
||||
func (c *Container) Close() error {
|
||||
if c != nil && c.db != nil {
|
||||
return c.db.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PutDevice stores the given device in this database. This should be called through Device.Save()
|
||||
// (which usually doesn't need to be called manually, as the library does that automatically when relevant).
|
||||
func (c *Container) PutDevice(device *store.Device) error {
|
||||
@ -229,7 +241,7 @@ func (c *Container) PutDevice(device *store.Device) error {
|
||||
device.ID.String(), device.RegistrationID, device.NoiseKey.Priv[:], device.IdentityKey.Priv[:],
|
||||
device.SignedPreKey.Priv[:], device.SignedPreKey.KeyID, device.SignedPreKey.Signature[:],
|
||||
device.AdvSecretKey, device.Account.Details, device.Account.AccountSignature, device.Account.AccountSignatureKey, device.Account.DeviceSignature,
|
||||
device.Platform, device.BusinessName, device.PushName)
|
||||
device.Platform, device.BusinessName, device.PushName, uuid.NullUUID{UUID: device.FacebookUUID, Valid: device.FacebookUUID != uuid.Nil})
|
||||
|
||||
if !device.Initialized {
|
||||
innerStore := NewSQLStore(c, *device.ID)
|
||||
|
@ -8,6 +8,7 @@ package sqlstore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type upgradeFunc func(*sql.Tx, *Container) error
|
||||
@ -16,7 +17,7 @@ type upgradeFunc func(*sql.Tx, *Container) error
|
||||
//
|
||||
// This may be of use if you want to manage the database fully manually, but in most cases you
|
||||
// should just call Container.Upgrade to let the library handle everything.
|
||||
var Upgrades = [...]upgradeFunc{upgradeV1, upgradeV2, upgradeV3, upgradeV4}
|
||||
var Upgrades = [...]upgradeFunc{upgradeV1, upgradeV2, upgradeV3, upgradeV4, upgradeV5, upgradeV6}
|
||||
|
||||
func (c *Container) getVersion() (int, error) {
|
||||
_, err := c.db.Exec("CREATE TABLE IF NOT EXISTS whatsmeow_version (version INTEGER)")
|
||||
@ -43,6 +44,16 @@ func (c *Container) setVersion(tx *sql.Tx, version int) error {
|
||||
|
||||
// Upgrade upgrades the database from the current to the latest version available.
|
||||
func (c *Container) Upgrade() error {
|
||||
if c.dialect == "sqlite" {
|
||||
var foreignKeysEnabled bool
|
||||
err := c.db.QueryRow("PRAGMA foreign_keys").Scan(&foreignKeysEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check if foreign keys are enabled: %w", err)
|
||||
} else if !foreignKeysEnabled {
|
||||
return fmt.Errorf("foreign keys are not enabled")
|
||||
}
|
||||
}
|
||||
|
||||
version, err := c.getVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -271,3 +282,13 @@ func upgradeV4(tx *sql.Tx, container *Container) error {
|
||||
)`)
|
||||
return err
|
||||
}
|
||||
|
||||
func upgradeV5(tx *sql.Tx, container *Container) error {
|
||||
_, err := tx.Exec("UPDATE whatsmeow_device SET jid=REPLACE(jid, '.0', '')")
|
||||
return err
|
||||
}
|
||||
|
||||
func upgradeV6(tx *sql.Tx, container *Container) error {
|
||||
_, err := tx.Exec("ALTER TABLE whatsmeow_device ADD COLUMN facebook_uuid uuid")
|
||||
return err
|
||||
}
|
||||
|
4
vendor/go.mau.fi/whatsmeow/store/store.go
vendored
4
vendor/go.mau.fi/whatsmeow/store/store.go
vendored
@ -11,6 +11,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
"go.mau.fi/whatsmeow/util/keys"
|
||||
@ -139,6 +141,8 @@ type Device struct {
|
||||
BusinessName string
|
||||
PushName string
|
||||
|
||||
FacebookUUID uuid.UUID
|
||||
|
||||
Initialized bool
|
||||
Identities IdentityStore
|
||||
Sessions SessionStore
|
||||
|
@ -142,6 +142,36 @@ type UserStatusMute struct {
|
||||
FromFullSync bool // Whether the action is emitted because of a fullSync
|
||||
}
|
||||
|
||||
// LabelEdit is emitted when a label is edited from any device.
|
||||
type LabelEdit struct {
|
||||
Timestamp time.Time // The time when the label was edited.
|
||||
LabelID string // The label id which was edited.
|
||||
|
||||
Action *waProto.LabelEditAction // The new label info.
|
||||
FromFullSync bool // Whether the action is emitted because of a fullSync
|
||||
}
|
||||
|
||||
// LabelAssociationChat is emitted when a chat is labeled or unlabeled from any device.
|
||||
type LabelAssociationChat struct {
|
||||
JID types.JID // The chat which was labeled or unlabeled.
|
||||
Timestamp time.Time // The time when the (un)labeling happened.
|
||||
LabelID string // The label id which was added or removed.
|
||||
|
||||
Action *waProto.LabelAssociationAction // The current label status of the chat.
|
||||
FromFullSync bool // Whether the action is emitted because of a fullSync
|
||||
}
|
||||
|
||||
// LabelAssociationMessage is emitted when a message is labeled or unlabeled from any device.
|
||||
type LabelAssociationMessage struct {
|
||||
JID types.JID // The chat which was labeled or unlabeled.
|
||||
Timestamp time.Time // The time when the (un)labeling happened.
|
||||
LabelID string // The label id which was added or removed.
|
||||
MessageID string // The message id which was labeled or unlabeled.
|
||||
|
||||
Action *waProto.LabelAssociationAction // The current label status of the message.
|
||||
FromFullSync bool // Whether the action is emitted because of a fullSync
|
||||
}
|
||||
|
||||
// AppState is emitted directly for new data received from app state syncing.
|
||||
// You should generally use the higher-level events like events.Contact and events.Mute.
|
||||
type AppState struct {
|
||||
|
14
vendor/go.mau.fi/whatsmeow/types/events/call.go
vendored
14
vendor/go.mau.fi/whatsmeow/types/events/call.go
vendored
@ -27,6 +27,20 @@ type CallAccept struct {
|
||||
Data *waBinary.Node
|
||||
}
|
||||
|
||||
type CallPreAccept struct {
|
||||
types.BasicCallMeta
|
||||
types.CallRemoteMeta
|
||||
|
||||
Data *waBinary.Node
|
||||
}
|
||||
|
||||
type CallTransport struct {
|
||||
types.BasicCallMeta
|
||||
types.CallRemoteMeta
|
||||
|
||||
Data *waBinary.Node
|
||||
}
|
||||
|
||||
// CallOfferNotice is emitted when the user receives a notice of a call on WhatsApp.
|
||||
// This seems to be primarily for group calls (whereas CallOffer is for 1:1 calls).
|
||||
type CallOfferNotice struct {
|
||||
|
163
vendor/go.mau.fi/whatsmeow/types/events/events.go
vendored
163
vendor/go.mau.fi/whatsmeow/types/events/events.go
vendored
@ -9,9 +9,13 @@ package events
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
waBinary "go.mau.fi/whatsmeow/binary"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMsgApplication"
|
||||
"go.mau.fi/whatsmeow/binary/armadillo/waMsgTransport"
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/types"
|
||||
)
|
||||
@ -69,6 +73,22 @@ type KeepAliveTimeout struct {
|
||||
// Note that if the websocket disconnects before the pings start working, this event will not be emitted.
|
||||
type KeepAliveRestored struct{}
|
||||
|
||||
// PermanentDisconnect is a class of events emitted when the client will not auto-reconnect by default.
|
||||
type PermanentDisconnect interface {
|
||||
PermanentDisconnectDescription() string
|
||||
}
|
||||
|
||||
func (l *LoggedOut) PermanentDisconnectDescription() string { return l.Reason.String() }
|
||||
func (*StreamReplaced) PermanentDisconnectDescription() string { return "stream replaced" }
|
||||
func (*ClientOutdated) PermanentDisconnectDescription() string { return "client outdated" }
|
||||
func (*CATRefreshError) PermanentDisconnectDescription() string { return "CAT refresh failed" }
|
||||
func (tb *TemporaryBan) PermanentDisconnectDescription() string {
|
||||
return fmt.Sprintf("temporarily banned: %s", tb.String())
|
||||
}
|
||||
func (cf *ConnectFailure) PermanentDisconnectDescription() string {
|
||||
return fmt.Sprintf("connect failure: %s", cf.Reason.String())
|
||||
}
|
||||
|
||||
// LoggedOut is emitted when the client has been unpaired from the phone.
|
||||
//
|
||||
// This can happen while connected (stream:error messages) or right after connecting (connect failure messages).
|
||||
@ -133,20 +153,22 @@ func (tb *TemporaryBan) String() string {
|
||||
type ConnectFailureReason int
|
||||
|
||||
const (
|
||||
ConnectFailureGeneric ConnectFailureReason = 400
|
||||
ConnectFailureLoggedOut ConnectFailureReason = 401
|
||||
ConnectFailureTempBanned ConnectFailureReason = 402
|
||||
ConnectFailureMainDeviceGone ConnectFailureReason = 403
|
||||
ConnectFailureUnknownLogout ConnectFailureReason = 406
|
||||
ConnectFailureMainDeviceGone ConnectFailureReason = 403 // this is now called LOCKED in the whatsapp web code
|
||||
ConnectFailureUnknownLogout ConnectFailureReason = 406 // this is now called BANNED in the whatsapp web code
|
||||
|
||||
ConnectFailureClientOutdated ConnectFailureReason = 405
|
||||
ConnectFailureBadUserAgent ConnectFailureReason = 409
|
||||
|
||||
// 400, 500 and 501 are also existing codes, but the meaning is unknown
|
||||
ConnectFailureCATExpired ConnectFailureReason = 413
|
||||
ConnectFailureCATInvalid ConnectFailureReason = 414
|
||||
ConnectFailureNotFound ConnectFailureReason = 415
|
||||
|
||||
// 503 doesn't seem to be included in the web app JS with the other codes, and it's very rare,
|
||||
// but does happen after a 503 stream error sometimes.
|
||||
|
||||
ConnectFailureServiceUnavailable ConnectFailureReason = 503
|
||||
ConnectFailureInternalServerError ConnectFailureReason = 500
|
||||
ConnectFailureExperimental ConnectFailureReason = 501
|
||||
ConnectFailureServiceUnavailable ConnectFailureReason = 503
|
||||
)
|
||||
|
||||
var connectFailureReasonMessage = map[ConnectFailureReason]string{
|
||||
@ -156,6 +178,8 @@ var connectFailureReasonMessage = map[ConnectFailureReason]string{
|
||||
ConnectFailureUnknownLogout: "logged out for unknown reason",
|
||||
ConnectFailureClientOutdated: "client is out of date",
|
||||
ConnectFailureBadUserAgent: "client user agent was rejected",
|
||||
ConnectFailureCATExpired: "messenger crypto auth token has expired",
|
||||
ConnectFailureCATInvalid: "messenger crypto auth token is invalid",
|
||||
}
|
||||
|
||||
// IsLoggedOut returns true if the client should delete session data due to this connect failure.
|
||||
@ -163,6 +187,10 @@ func (cfr ConnectFailureReason) IsLoggedOut() bool {
|
||||
return cfr == ConnectFailureLoggedOut || cfr == ConnectFailureMainDeviceGone || cfr == ConnectFailureUnknownLogout
|
||||
}
|
||||
|
||||
func (cfr ConnectFailureReason) NumberString() string {
|
||||
return strconv.Itoa(int(cfr))
|
||||
}
|
||||
|
||||
// String returns the reason code and a short human-readable description of the error.
|
||||
func (cfr ConnectFailureReason) String() string {
|
||||
msg, ok := connectFailureReasonMessage[cfr]
|
||||
@ -184,6 +212,10 @@ type ConnectFailure struct {
|
||||
// ClientOutdated is emitted when the WhatsApp server rejects the connection with the ConnectFailureClientOutdated code.
|
||||
type ClientOutdated struct{}
|
||||
|
||||
type CATRefreshError struct {
|
||||
Error error
|
||||
}
|
||||
|
||||
// StreamError is emitted when the WhatsApp server sends a <stream:error> node with an unknown code.
|
||||
//
|
||||
// Known codes are handled internally and emitted as different events (e.g. LoggedOut).
|
||||
@ -223,6 +255,14 @@ type UndecryptableMessage struct {
|
||||
DecryptFailMode DecryptFailMode
|
||||
}
|
||||
|
||||
type NewsletterMessageMeta struct {
|
||||
// When a newsletter message is edited, the message isn't wrapped in an EditedMessage like normal messages.
|
||||
// Instead, the message is the new content, the ID is the original message ID, and the edit timestamp is here.
|
||||
EditTS time.Time
|
||||
// This is the timestamp of the original message for edits.
|
||||
OriginalTS time.Time
|
||||
}
|
||||
|
||||
// Message is emitted when receiving a new message.
|
||||
type Message struct {
|
||||
Info types.MessageInfo // Information about the message like the chat and sender IDs
|
||||
@ -241,11 +281,24 @@ type Message struct {
|
||||
// If the message was re-requested from the sender, this is the number of retries it took.
|
||||
RetryCount int
|
||||
|
||||
NewsletterMeta *NewsletterMessageMeta
|
||||
|
||||
// The raw message struct. This is the raw unmodified data, which means the actual message might
|
||||
// be wrapped in DeviceSentMessage, EphemeralMessage or ViewOnceMessage.
|
||||
RawMessage *waProto.Message
|
||||
}
|
||||
|
||||
type FBMessage struct {
|
||||
Info types.MessageInfo // Information about the message like the chat and sender IDs
|
||||
Message armadillo.MessageApplicationSub // The actual message struct
|
||||
|
||||
// If the message was re-requested from the sender, this is the number of retries it took.
|
||||
RetryCount int
|
||||
|
||||
Transport *waMsgTransport.MessageTransport // The first level of wrapping the message was in
|
||||
Application *waMsgApplication.MessageApplication // The second level of wrapping the message was in
|
||||
}
|
||||
|
||||
// UnwrapRaw fills the Message, IsEphemeral and IsViewOnce fields based on the raw message in the RawMessage field.
|
||||
func (evt *Message) UnwrapRaw() *Message {
|
||||
evt.Message = evt.RawMessage
|
||||
@ -280,44 +333,19 @@ func (evt *Message) UnwrapRaw() *Message {
|
||||
return evt
|
||||
}
|
||||
|
||||
// ReceiptType represents the type of a Receipt event.
|
||||
type ReceiptType string
|
||||
// Deprecated: use types.ReceiptType directly
|
||||
type ReceiptType = types.ReceiptType
|
||||
|
||||
// Deprecated: use types.ReceiptType* constants directly
|
||||
const (
|
||||
// ReceiptTypeDelivered means the message was delivered to the device (but the user might not have noticed).
|
||||
ReceiptTypeDelivered ReceiptType = ""
|
||||
// ReceiptTypeSender is sent by your other devices when a message you sent is delivered to them.
|
||||
ReceiptTypeSender ReceiptType = "sender"
|
||||
// ReceiptTypeRetry means the message was delivered to the device, but decrypting the message failed.
|
||||
ReceiptTypeRetry ReceiptType = "retry"
|
||||
// ReceiptTypeRead means the user opened the chat and saw the message.
|
||||
ReceiptTypeRead ReceiptType = "read"
|
||||
// ReceiptTypeReadSelf means the current user read a message from a different device, and has read receipts disabled in privacy settings.
|
||||
ReceiptTypeReadSelf ReceiptType = "read-self"
|
||||
// ReceiptTypePlayed means the user opened a view-once media message.
|
||||
//
|
||||
// This is dispatched for both incoming and outgoing messages when played. If the current user opened the media,
|
||||
// it means the media should be removed from all devices. If a recipient opened the media, it's just a notification
|
||||
// for the sender that the media was viewed.
|
||||
ReceiptTypePlayed ReceiptType = "played"
|
||||
ReceiptTypeDelivered = types.ReceiptTypeDelivered
|
||||
ReceiptTypeSender = types.ReceiptTypeSender
|
||||
ReceiptTypeRetry = types.ReceiptTypeRetry
|
||||
ReceiptTypeRead = types.ReceiptTypeRead
|
||||
ReceiptTypeReadSelf = types.ReceiptTypeReadSelf
|
||||
ReceiptTypePlayed = types.ReceiptTypePlayed
|
||||
)
|
||||
|
||||
// GoString returns the name of the Go constant for the ReceiptType value.
|
||||
func (rt ReceiptType) GoString() string {
|
||||
switch rt {
|
||||
case ReceiptTypeRead:
|
||||
return "events.ReceiptTypeRead"
|
||||
case ReceiptTypeReadSelf:
|
||||
return "events.ReceiptTypeReadSelf"
|
||||
case ReceiptTypeDelivered:
|
||||
return "events.ReceiptTypeDelivered"
|
||||
case ReceiptTypePlayed:
|
||||
return "events.ReceiptTypePlayed"
|
||||
default:
|
||||
return fmt.Sprintf("events.ReceiptType(%#v)", string(rt))
|
||||
}
|
||||
}
|
||||
|
||||
// Receipt is emitted when an outgoing message is delivered to or read by another user, or when another device reads an incoming message.
|
||||
//
|
||||
// N.B. WhatsApp on Android sends message IDs from newest message to oldest, but WhatsApp on iOS sends them in the opposite order (oldest first).
|
||||
@ -325,7 +353,7 @@ type Receipt struct {
|
||||
types.MessageSource
|
||||
MessageIDs []types.MessageID
|
||||
Timestamp time.Time
|
||||
Type ReceiptType
|
||||
Type types.ReceiptType
|
||||
}
|
||||
|
||||
// ChatPresence is emitted when a chat state update (also known as typing notification) is received.
|
||||
@ -424,6 +452,8 @@ type PrivacySettings struct {
|
||||
StatusChanged bool
|
||||
ProfileChanged bool
|
||||
ReadReceiptsChanged bool
|
||||
OnlineChanged bool
|
||||
CallAddChanged bool
|
||||
}
|
||||
|
||||
// OfflineSyncPreview is emitted right after connecting if the server is going to send events that the client missed during downtime.
|
||||
@ -460,3 +490,52 @@ type MediaRetry struct {
|
||||
SenderID types.JID // The user who sent the message. Only present in groups.
|
||||
FromMe bool // Whether the message was sent by the current user or someone else.
|
||||
}
|
||||
|
||||
type BlocklistAction string
|
||||
|
||||
const (
|
||||
BlocklistActionDefault BlocklistAction = ""
|
||||
BlocklistActionModify BlocklistAction = "modify"
|
||||
)
|
||||
|
||||
// Blocklist is emitted when the user's blocked user list is changed.
|
||||
type Blocklist struct {
|
||||
// Action specifies what happened. If it's empty, there should be a list of changes in the Changes list.
|
||||
// If it's "modify", then the Changes list will be empty and the whole blocklist should be re-requested.
|
||||
Action BlocklistAction
|
||||
DHash string
|
||||
PrevDHash string
|
||||
Changes []BlocklistChange
|
||||
}
|
||||
|
||||
type BlocklistChangeAction string
|
||||
|
||||
const (
|
||||
BlocklistChangeActionBlock BlocklistChangeAction = "block"
|
||||
BlocklistChangeActionUnblock BlocklistChangeAction = "unblock"
|
||||
)
|
||||
|
||||
type BlocklistChange struct {
|
||||
JID types.JID
|
||||
Action BlocklistChangeAction
|
||||
}
|
||||
|
||||
type NewsletterJoin struct {
|
||||
types.NewsletterMetadata
|
||||
}
|
||||
|
||||
type NewsletterLeave struct {
|
||||
ID types.JID `json:"id"`
|
||||
Role types.NewsletterRole `json:"role"`
|
||||
}
|
||||
|
||||
type NewsletterMuteChange struct {
|
||||
ID types.JID `json:"id"`
|
||||
Mute types.NewsletterMuteState `json:"mute"`
|
||||
}
|
||||
|
||||
type NewsletterLiveUpdate struct {
|
||||
JID types.JID
|
||||
Time time.Time
|
||||
Messages []*types.NewsletterMessage
|
||||
}
|
||||
|
9
vendor/go.mau.fi/whatsmeow/types/group.go
vendored
9
vendor/go.mau.fi/whatsmeow/types/group.go
vendored
@ -26,6 +26,7 @@ type GroupInfo struct {
|
||||
GroupLocked
|
||||
GroupAnnounce
|
||||
GroupEphemeral
|
||||
GroupIncognito
|
||||
|
||||
GroupParent
|
||||
GroupLinkedParent
|
||||
@ -79,12 +80,20 @@ type GroupAnnounce struct {
|
||||
AnnounceVersionID string
|
||||
}
|
||||
|
||||
type GroupIncognito struct {
|
||||
IsIncognito bool
|
||||
}
|
||||
|
||||
// GroupParticipant contains info about a participant of a WhatsApp group chat.
|
||||
type GroupParticipant struct {
|
||||
JID JID
|
||||
LID JID
|
||||
IsAdmin bool
|
||||
IsSuperAdmin bool
|
||||
|
||||
// This is only present for anonymous users in announcement groups, it's an obfuscated phone number
|
||||
DisplayName string
|
||||
|
||||
// When creating groups, adding some participants may fail.
|
||||
// In such cases, the error code will be here.
|
||||
Error int
|
||||
|
153
vendor/go.mau.fi/whatsmeow/types/jid.go
vendored
153
vendor/go.mau.fi/whatsmeow/types/jid.go
vendored
@ -24,6 +24,10 @@ const (
|
||||
LegacyUserServer = "c.us"
|
||||
BroadcastServer = "broadcast"
|
||||
HiddenUserServer = "lid"
|
||||
MessengerServer = "msgr"
|
||||
InteropServer = "interop"
|
||||
NewsletterServer = "newsletter"
|
||||
HostedServer = "hosted"
|
||||
)
|
||||
|
||||
// Some JIDs that are contacted often.
|
||||
@ -40,17 +44,31 @@ var (
|
||||
// MessageID is the internal ID of a WhatsApp message.
|
||||
type MessageID = string
|
||||
|
||||
// MessageServerID is the server ID of a WhatsApp newsletter message.
|
||||
type MessageServerID = int
|
||||
|
||||
// JID represents a WhatsApp user ID.
|
||||
//
|
||||
// There are two types of JIDs: regular JID pairs (user and server) and AD-JIDs (user, agent and device).
|
||||
// AD JIDs are only used to refer to specific devices of users, so the server is always s.whatsapp.net (DefaultUserServer).
|
||||
// Regular JIDs can be used for entities on any servers (users, groups, broadcasts).
|
||||
type JID struct {
|
||||
User string
|
||||
Agent uint8
|
||||
Device uint8
|
||||
Server string
|
||||
AD bool
|
||||
User string
|
||||
RawAgent uint8
|
||||
Device uint16
|
||||
Integrator uint16
|
||||
Server string
|
||||
}
|
||||
|
||||
func (jid JID) ActualAgent() uint8 {
|
||||
switch jid.Server {
|
||||
case DefaultUserServer:
|
||||
return 0
|
||||
case HiddenUserServer:
|
||||
return 1
|
||||
default:
|
||||
return jid.RawAgent
|
||||
}
|
||||
}
|
||||
|
||||
// UserInt returns the user as an integer. This is only safe to run on normal users, not on groups or broadcast lists.
|
||||
@ -61,23 +79,27 @@ func (jid JID) UserInt() uint64 {
|
||||
|
||||
// ToNonAD returns a version of the JID struct that doesn't have the agent and device set.
|
||||
func (jid JID) ToNonAD() JID {
|
||||
if jid.AD {
|
||||
return JID{
|
||||
User: jid.User,
|
||||
Server: DefaultUserServer,
|
||||
}
|
||||
} else {
|
||||
return jid
|
||||
return JID{
|
||||
User: jid.User,
|
||||
Server: jid.Server,
|
||||
Integrator: jid.Integrator,
|
||||
}
|
||||
}
|
||||
|
||||
// SignalAddress returns the Signal protocol address for the user.
|
||||
func (jid JID) SignalAddress() *signalProtocol.SignalAddress {
|
||||
user := jid.User
|
||||
if jid.Agent != 0 {
|
||||
user = fmt.Sprintf("%s_%d", jid.User, jid.Agent)
|
||||
agent := jid.ActualAgent()
|
||||
if agent != 0 {
|
||||
user = fmt.Sprintf("%s_%d", jid.User, agent)
|
||||
}
|
||||
return signalProtocol.NewSignalAddress(user, uint32(jid.Device))
|
||||
// TODO use @lid suffix instead of agent?
|
||||
//suffix := ""
|
||||
//if jid.Server == HiddenUserServer {
|
||||
// suffix = "@lid"
|
||||
//}
|
||||
//return signalProtocol.NewSignalAddress(user, uint32(jid.Device), suffix)
|
||||
}
|
||||
|
||||
// IsBroadcastList returns true if the JID is a broadcast list, but not the status broadcast.
|
||||
@ -87,53 +109,70 @@ func (jid JID) IsBroadcastList() bool {
|
||||
|
||||
// NewADJID creates a new AD JID.
|
||||
func NewADJID(user string, agent, device uint8) JID {
|
||||
var server string
|
||||
switch agent {
|
||||
case 0:
|
||||
server = DefaultUserServer
|
||||
case 1:
|
||||
server = HiddenUserServer
|
||||
agent = 0
|
||||
default:
|
||||
if (agent&0x01) != 0 || (agent&0x80) == 0 { // agent % 2 == 0 || agent < 128?
|
||||
// TODO invalid JID?
|
||||
}
|
||||
server = HostedServer
|
||||
}
|
||||
return JID{
|
||||
User: user,
|
||||
Agent: agent,
|
||||
Device: device,
|
||||
Server: DefaultUserServer,
|
||||
AD: true,
|
||||
User: user,
|
||||
RawAgent: agent,
|
||||
Device: uint16(device),
|
||||
Server: server,
|
||||
}
|
||||
}
|
||||
|
||||
func parseADJID(user string) (JID, error) {
|
||||
var fullJID JID
|
||||
fullJID.AD = true
|
||||
fullJID.Server = DefaultUserServer
|
||||
|
||||
dotIndex := strings.IndexRune(user, '.')
|
||||
colonIndex := strings.IndexRune(user, ':')
|
||||
if dotIndex < 0 || colonIndex < 0 || colonIndex+1 <= dotIndex {
|
||||
return fullJID, fmt.Errorf("failed to parse ADJID: missing separators")
|
||||
}
|
||||
|
||||
fullJID.User = user[:dotIndex]
|
||||
agent, err := strconv.Atoi(user[dotIndex+1 : colonIndex])
|
||||
if err != nil {
|
||||
return fullJID, fmt.Errorf("failed to parse agent from JID: %w", err)
|
||||
} else if agent < 0 || agent > 255 {
|
||||
return fullJID, fmt.Errorf("failed to parse agent from JID: invalid value (%d)", agent)
|
||||
}
|
||||
device, err := strconv.Atoi(user[colonIndex+1:])
|
||||
if err != nil {
|
||||
return fullJID, fmt.Errorf("failed to parse device from JID: %w", err)
|
||||
} else if device < 0 || device > 255 {
|
||||
return fullJID, fmt.Errorf("failed to parse device from JID: invalid value (%d)", device)
|
||||
}
|
||||
fullJID.Agent = uint8(agent)
|
||||
fullJID.Device = uint8(device)
|
||||
return fullJID, nil
|
||||
}
|
||||
|
||||
// ParseJID parses a JID out of the given string. It supports both regular and AD JIDs.
|
||||
func ParseJID(jid string) (JID, error) {
|
||||
parts := strings.Split(jid, "@")
|
||||
if len(parts) == 1 {
|
||||
return NewJID("", parts[0]), nil
|
||||
} else if strings.ContainsRune(parts[0], ':') && strings.ContainsRune(parts[0], '.') && parts[1] == DefaultUserServer {
|
||||
return parseADJID(parts[0])
|
||||
}
|
||||
return NewJID(parts[0], parts[1]), nil
|
||||
parsedJID := JID{User: parts[0], Server: parts[1]}
|
||||
if strings.ContainsRune(parsedJID.User, '.') {
|
||||
parts = strings.Split(parsedJID.User, ".")
|
||||
if len(parts) != 2 {
|
||||
return parsedJID, fmt.Errorf("unexpected number of dots in JID")
|
||||
}
|
||||
parsedJID.User = parts[0]
|
||||
ad := parts[1]
|
||||
parts = strings.Split(ad, ":")
|
||||
if len(parts) > 2 {
|
||||
return parsedJID, fmt.Errorf("unexpected number of colons in JID")
|
||||
}
|
||||
agent, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return parsedJID, fmt.Errorf("failed to parse device from JID: %w", err)
|
||||
}
|
||||
parsedJID.RawAgent = uint8(agent)
|
||||
if len(parts) == 2 {
|
||||
device, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return parsedJID, fmt.Errorf("failed to parse device from JID: %w", err)
|
||||
}
|
||||
parsedJID.Device = uint16(device)
|
||||
}
|
||||
} else if strings.ContainsRune(parsedJID.User, ':') {
|
||||
parts = strings.Split(parsedJID.User, ":")
|
||||
if len(parts) != 2 {
|
||||
return parsedJID, fmt.Errorf("unexpected number of colons in JID")
|
||||
}
|
||||
parsedJID.User = parts[0]
|
||||
device, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return parsedJID, fmt.Errorf("failed to parse device from JID: %w", err)
|
||||
}
|
||||
parsedJID.Device = uint16(device)
|
||||
}
|
||||
return parsedJID, nil
|
||||
}
|
||||
|
||||
// NewJID creates a new regular JID.
|
||||
@ -144,11 +183,17 @@ func NewJID(user, server string) JID {
|
||||
}
|
||||
}
|
||||
|
||||
func (jid JID) ADString() string {
|
||||
return fmt.Sprintf("%s.%d:%d@%s", jid.User, jid.RawAgent, jid.Device, jid.Server)
|
||||
}
|
||||
|
||||
// String converts the JID to a string representation.
|
||||
// The output string can be parsed with ParseJID, except for JIDs with no User part specified.
|
||||
// The output string can be parsed with ParseJID.
|
||||
func (jid JID) String() string {
|
||||
if jid.AD {
|
||||
return fmt.Sprintf("%s.%d:%d@%s", jid.User, jid.Agent, jid.Device, jid.Server)
|
||||
if jid.RawAgent > 0 {
|
||||
return fmt.Sprintf("%s.%d:%d@%s", jid.User, jid.RawAgent, jid.Device, jid.Server)
|
||||
} else if jid.Device > 0 {
|
||||
return fmt.Sprintf("%s:%d@%s", jid.User, jid.Device, jid.Server)
|
||||
} else if len(jid.User) > 0 {
|
||||
return fmt.Sprintf("%s@%s", jid.User, jid.Server)
|
||||
} else {
|
||||
|
15
vendor/go.mau.fi/whatsmeow/types/message.go
vendored
15
vendor/go.mau.fi/whatsmeow/types/message.go
vendored
@ -36,16 +36,29 @@ type DeviceSentMeta struct {
|
||||
Phash string
|
||||
}
|
||||
|
||||
type EditAttribute string
|
||||
|
||||
const (
|
||||
EditAttributeEmpty EditAttribute = ""
|
||||
EditAttributeMessageEdit EditAttribute = "1"
|
||||
EditAttributePinInChat EditAttribute = "2"
|
||||
EditAttributeAdminEdit EditAttribute = "3" // only used in newsletters
|
||||
EditAttributeSenderRevoke EditAttribute = "7"
|
||||
EditAttributeAdminRevoke EditAttribute = "8"
|
||||
)
|
||||
|
||||
// MessageInfo contains metadata about an incoming message.
|
||||
type MessageInfo struct {
|
||||
MessageSource
|
||||
ID string
|
||||
ID MessageID
|
||||
ServerID MessageServerID
|
||||
Type string
|
||||
PushName string
|
||||
Timestamp time.Time
|
||||
Category string
|
||||
Multicast bool
|
||||
MediaType string
|
||||
Edit EditAttribute
|
||||
|
||||
VerifiedName *VerifiedName
|
||||
DeviceSentMeta *DeviceSentMeta // Metadata for direct messages sent from another one of the user's own devices.
|
||||
|
197
vendor/go.mau.fi/whatsmeow/types/newsletter.go
vendored
Normal file
197
vendor/go.mau.fi/whatsmeow/types/newsletter.go
vendored
Normal file
@ -0,0 +1,197 @@
|
||||
// Copyright (c) 2023 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 types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"go.mau.fi/util/jsontime"
|
||||
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
)
|
||||
|
||||
type NewsletterVerificationState string
|
||||
|
||||
func (nvs *NewsletterVerificationState) UnmarshalText(text []byte) error {
|
||||
*nvs = NewsletterVerificationState(bytes.ToLower(text))
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
NewsletterVerificationStateVerified NewsletterVerificationState = "verified"
|
||||
NewsletterVerificationStateUnverified NewsletterVerificationState = "unverified"
|
||||
)
|
||||
|
||||
type NewsletterPrivacy string
|
||||
|
||||
func (np *NewsletterPrivacy) UnmarshalText(text []byte) error {
|
||||
*np = NewsletterPrivacy(bytes.ToLower(text))
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
NewsletterPrivacyPrivate NewsletterPrivacy = "private"
|
||||
NewsletterPrivacyPublic NewsletterPrivacy = "public"
|
||||
)
|
||||
|
||||
type NewsletterReactionsMode string
|
||||
|
||||
const (
|
||||
NewsletterReactionsModeAll NewsletterReactionsMode = "all"
|
||||
NewsletterReactionsModeBasic NewsletterReactionsMode = "basic"
|
||||
NewsletterReactionsModeNone NewsletterReactionsMode = "none"
|
||||
NewsletterReactionsModeBlocklist NewsletterReactionsMode = "blocklist"
|
||||
)
|
||||
|
||||
type NewsletterState string
|
||||
|
||||
func (ns *NewsletterState) UnmarshalText(text []byte) error {
|
||||
*ns = NewsletterState(bytes.ToLower(text))
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
NewsletterStateActive NewsletterState = "active"
|
||||
NewsletterStateSuspended NewsletterState = "suspended"
|
||||
NewsletterStateGeoSuspended NewsletterState = "geosuspended"
|
||||
)
|
||||
|
||||
type NewsletterMuted struct {
|
||||
Muted bool
|
||||
}
|
||||
|
||||
type WrappedNewsletterState struct {
|
||||
Type NewsletterState `json:"type"`
|
||||
}
|
||||
|
||||
type NewsletterMuteState string
|
||||
|
||||
func (nms *NewsletterMuteState) UnmarshalText(text []byte) error {
|
||||
*nms = NewsletterMuteState(bytes.ToLower(text))
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
NewsletterMuteOn NewsletterMuteState = "on"
|
||||
NewsletterMuteOff NewsletterMuteState = "off"
|
||||
)
|
||||
|
||||
type NewsletterRole string
|
||||
|
||||
func (nr *NewsletterRole) UnmarshalText(text []byte) error {
|
||||
*nr = NewsletterRole(bytes.ToLower(text))
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
NewsletterRoleSubscriber NewsletterRole = "subscriber"
|
||||
NewsletterRoleGuest NewsletterRole = "guest"
|
||||
NewsletterRoleAdmin NewsletterRole = "admin"
|
||||
NewsletterRoleOwner NewsletterRole = "owner"
|
||||
)
|
||||
|
||||
type NewsletterMetadata struct {
|
||||
ID JID `json:"id"`
|
||||
State WrappedNewsletterState `json:"state"`
|
||||
ThreadMeta NewsletterThreadMetadata `json:"thread_metadata"`
|
||||
ViewerMeta *NewsletterViewerMetadata `json:"viewer_metadata"`
|
||||
}
|
||||
|
||||
type NewsletterViewerMetadata struct {
|
||||
Mute NewsletterMuteState `json:"mute"`
|
||||
Role NewsletterRole `json:"role"`
|
||||
}
|
||||
|
||||
type NewsletterKeyType string
|
||||
|
||||
const (
|
||||
NewsletterKeyTypeJID NewsletterKeyType = "JID"
|
||||
NewsletterKeyTypeInvite NewsletterKeyType = "INVITE"
|
||||
)
|
||||
|
||||
type NewsletterReactionSettings struct {
|
||||
Value NewsletterReactionsMode `json:"value"`
|
||||
}
|
||||
|
||||
type NewsletterSettings struct {
|
||||
ReactionCodes NewsletterReactionSettings `json:"reaction_codes"`
|
||||
}
|
||||
|
||||
type NewsletterThreadMetadata struct {
|
||||
CreationTime jsontime.UnixString `json:"creation_time"`
|
||||
InviteCode string `json:"invite"`
|
||||
Name NewsletterText `json:"name"`
|
||||
Description NewsletterText `json:"description"`
|
||||
SubscriberCount int `json:"subscribers_count,string"`
|
||||
VerificationState NewsletterVerificationState `json:"verification"`
|
||||
Picture *ProfilePictureInfo `json:"picture"`
|
||||
Preview ProfilePictureInfo `json:"preview"`
|
||||
Settings NewsletterSettings `json:"settings"`
|
||||
|
||||
//NewsletterMuted `json:"-"`
|
||||
//PrivacyType NewsletterPrivacy `json:"-"`
|
||||
//ReactionsMode NewsletterReactionsMode `json:"-"`
|
||||
//State NewsletterState `json:"-"`
|
||||
}
|
||||
|
||||
type NewsletterText struct {
|
||||
Text string `json:"text"`
|
||||
ID string `json:"id"`
|
||||
UpdateTime jsontime.UnixMicroString `json:"update_time"`
|
||||
}
|
||||
|
||||
type NewsletterMessage struct {
|
||||
MessageServerID MessageServerID
|
||||
ViewsCount int
|
||||
ReactionCounts map[string]int
|
||||
|
||||
// This is only present when fetching messages, not in live updates
|
||||
Message *waProto.Message
|
||||
}
|
||||
|
||||
type GraphQLErrorExtensions struct {
|
||||
ErrorCode int `json:"error_code"`
|
||||
IsRetryable bool `json:"is_retryable"`
|
||||
Severity string `json:"severity"`
|
||||
}
|
||||
|
||||
type GraphQLError struct {
|
||||
Extensions GraphQLErrorExtensions `json:"extensions"`
|
||||
Message string `json:"message"`
|
||||
Path []string `json:"path"`
|
||||
}
|
||||
|
||||
func (gqle GraphQLError) Error() string {
|
||||
return fmt.Sprintf("%d %s (%s)", gqle.Extensions.ErrorCode, gqle.Message, gqle.Extensions.Severity)
|
||||
}
|
||||
|
||||
type GraphQLErrors []GraphQLError
|
||||
|
||||
func (gqles GraphQLErrors) Unwrap() []error {
|
||||
errs := make([]error, len(gqles))
|
||||
for i, gqle := range gqles {
|
||||
errs[i] = gqle
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func (gqles GraphQLErrors) Error() string {
|
||||
if len(gqles) == 0 {
|
||||
return ""
|
||||
} else if len(gqles) == 1 {
|
||||
return gqles[0].Error()
|
||||
} else {
|
||||
return fmt.Sprintf("%v (and %d other errors)", gqles[0], len(gqles)-1)
|
||||
}
|
||||
}
|
||||
|
||||
type GraphQLResponse struct {
|
||||
Data json.RawMessage `json:"data"`
|
||||
Errors GraphQLErrors `json:"errors"`
|
||||
}
|
50
vendor/go.mau.fi/whatsmeow/types/presence.go
vendored
50
vendor/go.mau.fi/whatsmeow/types/presence.go
vendored
@ -6,6 +6,10 @@
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Presence string
|
||||
|
||||
const (
|
||||
@ -26,3 +30,49 @@ const (
|
||||
ChatPresenceMediaText ChatPresenceMedia = ""
|
||||
ChatPresenceMediaAudio ChatPresenceMedia = "audio"
|
||||
)
|
||||
|
||||
// ReceiptType represents the type of a Receipt event.
|
||||
type ReceiptType string
|
||||
|
||||
const (
|
||||
// ReceiptTypeDelivered means the message was delivered to the device (but the user might not have noticed).
|
||||
ReceiptTypeDelivered ReceiptType = ""
|
||||
// ReceiptTypeSender is sent by your other devices when a message you sent is delivered to them.
|
||||
ReceiptTypeSender ReceiptType = "sender"
|
||||
// ReceiptTypeRetry means the message was delivered to the device, but decrypting the message failed.
|
||||
ReceiptTypeRetry ReceiptType = "retry"
|
||||
// ReceiptTypeRead means the user opened the chat and saw the message.
|
||||
ReceiptTypeRead ReceiptType = "read"
|
||||
// ReceiptTypeReadSelf means the current user read a message from a different device, and has read receipts disabled in privacy settings.
|
||||
ReceiptTypeReadSelf ReceiptType = "read-self"
|
||||
// ReceiptTypePlayed means the user opened a view-once media message.
|
||||
//
|
||||
// This is dispatched for both incoming and outgoing messages when played. If the current user opened the media,
|
||||
// it means the media should be removed from all devices. If a recipient opened the media, it's just a notification
|
||||
// for the sender that the media was viewed.
|
||||
ReceiptTypePlayed ReceiptType = "played"
|
||||
// ReceiptTypePlayedSelf probably means the current user opened a view-once media message from a different device,
|
||||
// and has read receipts disabled in privacy settings.
|
||||
ReceiptTypePlayedSelf ReceiptType = "played-self"
|
||||
|
||||
ReceiptTypeServerError ReceiptType = "server-error"
|
||||
ReceiptTypeInactive ReceiptType = "inactive"
|
||||
ReceiptTypePeerMsg ReceiptType = "peer_msg"
|
||||
ReceiptTypeHistorySync ReceiptType = "hist_sync"
|
||||
)
|
||||
|
||||
// GoString returns the name of the Go constant for the ReceiptType value.
|
||||
func (rt ReceiptType) GoString() string {
|
||||
switch rt {
|
||||
case ReceiptTypeRead:
|
||||
return "types.ReceiptTypeRead"
|
||||
case ReceiptTypeReadSelf:
|
||||
return "types.ReceiptTypeReadSelf"
|
||||
case ReceiptTypeDelivered:
|
||||
return "types.ReceiptTypeDelivered"
|
||||
case ReceiptTypePlayed:
|
||||
return "types.ReceiptTypePlayed"
|
||||
default:
|
||||
return fmt.Sprintf("types.ReceiptType(%#v)", string(rt))
|
||||
}
|
||||
}
|
||||
|
75
vendor/go.mau.fi/whatsmeow/types/user.go
vendored
75
vendor/go.mau.fi/whatsmeow/types/user.go
vendored
@ -28,11 +28,11 @@ type UserInfo struct {
|
||||
|
||||
// ProfilePictureInfo contains the ID and URL for a WhatsApp user's profile picture or group's photo.
|
||||
type ProfilePictureInfo struct {
|
||||
URL string // The full URL for the image, can be downloaded with a simple HTTP request.
|
||||
ID string // The ID of the image. This is the same as UserInfo.PictureID.
|
||||
Type string // The type of image. Known types include "image" (full res) and "preview" (thumbnail).
|
||||
URL string `json:"url"` // The full URL for the image, can be downloaded with a simple HTTP request.
|
||||
ID string `json:"id"` // The ID of the image. This is the same as UserInfo.PictureID.
|
||||
Type string `json:"type"` // The type of image. Known types include "image" (full res) and "preview" (thumbnail).
|
||||
|
||||
DirectPath string // The path to the image, probably not very useful
|
||||
DirectPath string `json:"direct_path"` // The path to the image, probably not very useful
|
||||
}
|
||||
|
||||
// ContactInfo contains the cached names of a WhatsApp user.
|
||||
@ -87,19 +87,37 @@ type PrivacySetting string
|
||||
|
||||
// Possible privacy setting values.
|
||||
const (
|
||||
PrivacySettingUndefined PrivacySetting = ""
|
||||
PrivacySettingAll PrivacySetting = "all"
|
||||
PrivacySettingContacts PrivacySetting = "contacts"
|
||||
PrivacySettingNone PrivacySetting = "none"
|
||||
PrivacySettingUndefined PrivacySetting = ""
|
||||
PrivacySettingAll PrivacySetting = "all"
|
||||
PrivacySettingContacts PrivacySetting = "contacts"
|
||||
PrivacySettingContactBlacklist PrivacySetting = "contact_blacklist"
|
||||
PrivacySettingMatchLastSeen PrivacySetting = "match_last_seen"
|
||||
PrivacySettingKnown PrivacySetting = "known"
|
||||
PrivacySettingNone PrivacySetting = "none"
|
||||
)
|
||||
|
||||
// PrivacySettingType is the type of privacy setting.
|
||||
type PrivacySettingType string
|
||||
|
||||
const (
|
||||
PrivacySettingTypeGroupAdd PrivacySettingType = "groupadd" // Valid values: PrivacySettingAll, PrivacySettingContacts, PrivacySettingContactBlacklist, PrivacySettingNone
|
||||
PrivacySettingTypeLastSeen PrivacySettingType = "last" // Valid values: PrivacySettingAll, PrivacySettingContacts, PrivacySettingContactBlacklist, PrivacySettingNone
|
||||
PrivacySettingTypeStatus PrivacySettingType = "status" // Valid values: PrivacySettingAll, PrivacySettingContacts, PrivacySettingContactBlacklist, PrivacySettingNone
|
||||
PrivacySettingTypeProfile PrivacySettingType = "profile" // Valid values: PrivacySettingAll, PrivacySettingContacts, PrivacySettingContactBlacklist, PrivacySettingNone
|
||||
PrivacySettingTypeReadReceipts PrivacySettingType = "readreceipts" // Valid values: PrivacySettingAll, PrivacySettingNone
|
||||
PrivacySettingTypeOnline PrivacySettingType = "online" // Valid values: PrivacySettingAll, PrivacySettingMatchLastSeen
|
||||
PrivacySettingTypeCallAdd PrivacySettingType = "calladd" // Valid values: PrivacySettingAll, PrivacySettingKnown
|
||||
)
|
||||
|
||||
// PrivacySettings contains the user's privacy settings.
|
||||
type PrivacySettings struct {
|
||||
GroupAdd PrivacySetting
|
||||
LastSeen PrivacySetting
|
||||
Status PrivacySetting
|
||||
Profile PrivacySetting
|
||||
ReadReceipts PrivacySetting
|
||||
GroupAdd PrivacySetting // Valid values: PrivacySettingAll, PrivacySettingContacts, PrivacySettingContactBlacklist, PrivacySettingNone
|
||||
LastSeen PrivacySetting // Valid values: PrivacySettingAll, PrivacySettingContacts, PrivacySettingContactBlacklist, PrivacySettingNone
|
||||
Status PrivacySetting // Valid values: PrivacySettingAll, PrivacySettingContacts, PrivacySettingContactBlacklist, PrivacySettingNone
|
||||
Profile PrivacySetting // Valid values: PrivacySettingAll, PrivacySettingContacts, PrivacySettingContactBlacklist, PrivacySettingNone
|
||||
ReadReceipts PrivacySetting // Valid values: PrivacySettingAll, PrivacySettingNone
|
||||
CallAdd PrivacySetting // Valid values: PrivacySettingAll, PrivacySettingKnown
|
||||
Online PrivacySetting // Valid values: PrivacySettingAll, PrivacySettingMatchLastSeen
|
||||
}
|
||||
|
||||
// StatusPrivacyType is the type of list in StatusPrivacy.
|
||||
@ -121,3 +139,34 @@ type StatusPrivacy struct {
|
||||
|
||||
IsDefault bool
|
||||
}
|
||||
|
||||
// Blocklist contains the user's current list of blocked users.
|
||||
type Blocklist struct {
|
||||
DHash string // TODO is this just a timestamp?
|
||||
JIDs []JID
|
||||
}
|
||||
|
||||
// BusinessHoursConfig contains business operating hours of a WhatsApp business.
|
||||
type BusinessHoursConfig struct {
|
||||
DayOfWeek string
|
||||
Mode string
|
||||
OpenTime string
|
||||
CloseTime string
|
||||
}
|
||||
|
||||
// Category contains a WhatsApp business category.
|
||||
type Category struct {
|
||||
ID string
|
||||
Name string
|
||||
}
|
||||
|
||||
// BusinessProfile contains the profile information of a WhatsApp business.
|
||||
type BusinessProfile struct {
|
||||
JID JID
|
||||
Address string
|
||||
Email string
|
||||
Categories []Category
|
||||
ProfileOptions map[string]string
|
||||
BusinessHoursTimeZone string
|
||||
BusinessHours []BusinessHoursConfig
|
||||
}
|
||||
|
97
vendor/go.mau.fi/whatsmeow/upload.go
vendored
97
vendor/go.mau.fi/whatsmeow/upload.go
vendored
@ -17,15 +17,18 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"go.mau.fi/util/random"
|
||||
|
||||
"go.mau.fi/whatsmeow/socket"
|
||||
"go.mau.fi/whatsmeow/util/cbcutil"
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
// UploadResponse contains the data from the attachment upload, which can be put into a message to send the attachment.
|
||||
type UploadResponse struct {
|
||||
URL string `json:"url"`
|
||||
DirectPath string `json:"direct_path"`
|
||||
Handle string `json:"handle"`
|
||||
ObjectID string `json:"object_id"`
|
||||
|
||||
MediaKey []byte `json:"-"`
|
||||
FileEncSHA256 []byte `json:"-"`
|
||||
@ -62,7 +65,7 @@ type UploadResponse struct {
|
||||
// The same applies to the other message types like DocumentMessage, just replace the struct type and Message field name.
|
||||
func (cli *Client) Upload(ctx context.Context, plaintext []byte, appInfo MediaType) (resp UploadResponse, err error) {
|
||||
resp.FileLength = uint64(len(plaintext))
|
||||
resp.MediaKey = randbytes.Make(32)
|
||||
resp.MediaKey = random.Bytes(32)
|
||||
|
||||
plaintextSHA256 := sha256.Sum256(plaintext)
|
||||
resp.FileSHA256 = plaintextSHA256[:]
|
||||
@ -81,41 +84,99 @@ func (cli *Client) Upload(ctx context.Context, plaintext []byte, appInfo MediaTy
|
||||
h.Write(ciphertext)
|
||||
dataToUpload := append(ciphertext, h.Sum(nil)[:10]...)
|
||||
|
||||
fileEncSHA256 := sha256.Sum256(dataToUpload)
|
||||
resp.FileEncSHA256 = fileEncSHA256[:]
|
||||
dataHash := sha256.Sum256(dataToUpload)
|
||||
resp.FileEncSHA256 = dataHash[:]
|
||||
|
||||
var mediaConn *MediaConn
|
||||
mediaConn, err = cli.refreshMediaConn(false)
|
||||
err = cli.rawUpload(ctx, dataToUpload, resp.FileEncSHA256, appInfo, false, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// UploadNewsletter uploads the given attachment to WhatsApp servers without encrypting it first.
|
||||
//
|
||||
// Newsletter media works mostly the same way as normal media, with a few differences:
|
||||
// * Since it's unencrypted, there's no MediaKey or FileEncSha256 fields.
|
||||
// * There's a "media handle" that needs to be passed in SendRequestExtra.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// resp, err := cli.UploadNewsletter(context.Background(), yourImageBytes, whatsmeow.MediaImage)
|
||||
// // handle error
|
||||
//
|
||||
// imageMsg := &waProto.ImageMessage{
|
||||
// // Caption, mime type and other such fields work like normal
|
||||
// Caption: proto.String("Hello, world!"),
|
||||
// Mimetype: proto.String("image/png"),
|
||||
//
|
||||
// // URL and direct path are also there like normal media
|
||||
// Url: &resp.URL,
|
||||
// DirectPath: &resp.DirectPath,
|
||||
// FileSha256: resp.FileSha256,
|
||||
// FileLength: &resp.FileLength,
|
||||
// // Newsletter media isn't encrypted, so the media key and file enc sha fields are not applicable
|
||||
// }
|
||||
// _, err = cli.SendMessage(context.Background(), newsletterJID, &waProto.Message{
|
||||
// ImageMessage: imageMsg,
|
||||
// }, whatsmeow.SendRequestExtra{
|
||||
// // Unlike normal media, newsletters also include a "media handle" in the send request.
|
||||
// MediaHandle: resp.Handle,
|
||||
// })
|
||||
// // handle error again
|
||||
func (cli *Client) UploadNewsletter(ctx context.Context, data []byte, appInfo MediaType) (resp UploadResponse, err error) {
|
||||
resp.FileLength = uint64(len(data))
|
||||
hash := sha256.Sum256(data)
|
||||
resp.FileSHA256 = hash[:]
|
||||
err = cli.rawUpload(ctx, data, resp.FileSHA256, appInfo, true, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) rawUpload(ctx context.Context, dataToUpload, fileHash []byte, appInfo MediaType, newsletter bool, resp *UploadResponse) error {
|
||||
mediaConn, err := cli.refreshMediaConn(false)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to refresh media connections: %w", err)
|
||||
return
|
||||
return fmt.Errorf("failed to refresh media connections: %w", err)
|
||||
}
|
||||
|
||||
token := base64.URLEncoding.EncodeToString(resp.FileEncSHA256)
|
||||
token := base64.URLEncoding.EncodeToString(fileHash)
|
||||
q := url.Values{
|
||||
"auth": []string{mediaConn.Auth},
|
||||
"token": []string{token},
|
||||
}
|
||||
mmsType := mediaTypeToMMSType[appInfo]
|
||||
uploadPrefix := "mms"
|
||||
if cli.MessengerConfig != nil {
|
||||
uploadPrefix = "wa-msgr/mms"
|
||||
// Messenger upload only allows voice messages, not audio files
|
||||
if mmsType == "audio" {
|
||||
mmsType = "ptt"
|
||||
}
|
||||
}
|
||||
if newsletter {
|
||||
mmsType = fmt.Sprintf("newsletter-%s", mmsType)
|
||||
uploadPrefix = "newsletter"
|
||||
}
|
||||
var host string
|
||||
// Hacky hack to prefer last option (rupload.facebook.com) for messenger uploads.
|
||||
// For some reason, the primary host doesn't work, even though it has the <upload/> tag.
|
||||
if cli.MessengerConfig != nil {
|
||||
host = mediaConn.Hosts[len(mediaConn.Hosts)-1].Hostname
|
||||
} else {
|
||||
host = mediaConn.Hosts[0].Hostname
|
||||
}
|
||||
uploadURL := url.URL{
|
||||
Scheme: "https",
|
||||
Host: mediaConn.Hosts[0].Hostname,
|
||||
Path: fmt.Sprintf("/mms/%s/%s", mmsType, token),
|
||||
Host: host,
|
||||
Path: fmt.Sprintf("/%s/%s/%s", uploadPrefix, mmsType, token),
|
||||
RawQuery: q.Encode(),
|
||||
}
|
||||
|
||||
var req *http.Request
|
||||
req, err = http.NewRequestWithContext(ctx, http.MethodPost, uploadURL.String(), bytes.NewReader(dataToUpload))
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL.String(), bytes.NewReader(dataToUpload))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to prepare request: %w", err)
|
||||
return
|
||||
return fmt.Errorf("failed to prepare request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Origin", socket.Origin)
|
||||
req.Header.Set("Referer", socket.Origin+"/")
|
||||
|
||||
var httpResp *http.Response
|
||||
httpResp, err = cli.http.Do(req)
|
||||
httpResp, err := cli.http.Do(req)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to execute request: %w", err)
|
||||
} else if httpResp.StatusCode != http.StatusOK {
|
||||
@ -126,5 +187,5 @@ func (cli *Client) Upload(ctx context.Context, plaintext []byte, appInfo MediaTy
|
||||
if httpResp != nil {
|
||||
_ = httpResp.Body.Close()
|
||||
}
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
248
vendor/go.mau.fi/whatsmeow/user.go
vendored
248
vendor/go.mau.fi/whatsmeow/user.go
vendored
@ -24,6 +24,7 @@ const BusinessMessageLinkPrefix = "https://wa.me/message/"
|
||||
const ContactQRLinkPrefix = "https://wa.me/qr/"
|
||||
const BusinessMessageLinkDirectPrefix = "https://api.whatsapp.com/message/"
|
||||
const ContactQRLinkDirectPrefix = "https://api.whatsapp.com/qr/"
|
||||
const NewsletterLinkPrefix = "https://whatsapp.com/channel/"
|
||||
|
||||
// ResolveBusinessMessageLink resolves a business message short link and returns the target JID, business name and
|
||||
// text to prefill in the input field (if any).
|
||||
@ -226,6 +227,91 @@ func (cli *Client) GetUserInfo(jids []types.JID) (map[types.JID]types.UserInfo,
|
||||
return respData, nil
|
||||
}
|
||||
|
||||
func (cli *Client) parseBusinessProfile(node *waBinary.Node) (*types.BusinessProfile, error) {
|
||||
profileNode := node.GetChildByTag("profile")
|
||||
jid, ok := profileNode.AttrGetter().GetJID("jid", true)
|
||||
if !ok {
|
||||
return nil, errors.New("missing jid in business profile")
|
||||
}
|
||||
address := string(profileNode.GetChildByTag("address").Content.([]byte))
|
||||
email := string(profileNode.GetChildByTag("email").Content.([]byte))
|
||||
businessHour := profileNode.GetChildByTag("business_hours")
|
||||
businessHourTimezone := businessHour.AttrGetter().String("timezone")
|
||||
businessHoursConfigs := businessHour.GetChildren()
|
||||
businessHours := make([]types.BusinessHoursConfig, 0)
|
||||
for _, config := range businessHoursConfigs {
|
||||
if config.Tag != "business_hours_config" {
|
||||
continue
|
||||
}
|
||||
dow := config.AttrGetter().String("dow")
|
||||
mode := config.AttrGetter().String("mode")
|
||||
openTime := config.AttrGetter().String("open_time")
|
||||
closeTime := config.AttrGetter().String("close_time")
|
||||
businessHours = append(businessHours, types.BusinessHoursConfig{
|
||||
DayOfWeek: dow,
|
||||
Mode: mode,
|
||||
OpenTime: openTime,
|
||||
CloseTime: closeTime,
|
||||
})
|
||||
}
|
||||
categoriesNode := profileNode.GetChildByTag("categories")
|
||||
categories := make([]types.Category, 0)
|
||||
for _, category := range categoriesNode.GetChildren() {
|
||||
if category.Tag != "category" {
|
||||
continue
|
||||
}
|
||||
id := category.AttrGetter().String("id")
|
||||
name := string(category.Content.([]byte))
|
||||
categories = append(categories, types.Category{
|
||||
ID: id,
|
||||
Name: name,
|
||||
})
|
||||
}
|
||||
profileOptionsNode := profileNode.GetChildByTag("profile_options")
|
||||
profileOptions := make(map[string]string)
|
||||
for _, option := range profileOptionsNode.GetChildren() {
|
||||
profileOptions[option.Tag] = string(option.Content.([]byte))
|
||||
}
|
||||
return &types.BusinessProfile{
|
||||
JID: jid,
|
||||
Email: email,
|
||||
Address: address,
|
||||
Categories: categories,
|
||||
ProfileOptions: profileOptions,
|
||||
BusinessHoursTimeZone: businessHourTimezone,
|
||||
BusinessHours: businessHours,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetBusinessProfile gets the profile info of a WhatsApp business account
|
||||
func (cli *Client) GetBusinessProfile(jid types.JID) (*types.BusinessProfile, error) {
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Type: iqGet,
|
||||
To: types.ServerJID,
|
||||
Namespace: "w:biz",
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "business_profile",
|
||||
Attrs: waBinary.Attrs{
|
||||
"v": "244",
|
||||
},
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "profile",
|
||||
Attrs: waBinary.Attrs{
|
||||
"jid": jid,
|
||||
},
|
||||
}},
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, ok := resp.GetOptionalChildByTag("business_profile")
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: "business_profile", In: "response to business profile query"}
|
||||
}
|
||||
return cli.parseBusinessProfile(&node)
|
||||
}
|
||||
|
||||
// GetUserDevices gets the list of devices that the given user has. The input should be a list of
|
||||
// regular JIDs, and the output will be a list of AD JIDs. The local device will not be included in
|
||||
// the output even if the user's JID is included in the input. All other devices will be included.
|
||||
@ -237,34 +323,50 @@ func (cli *Client) GetUserDevicesContext(ctx context.Context, jids []types.JID)
|
||||
cli.userDevicesCacheLock.Lock()
|
||||
defer cli.userDevicesCacheLock.Unlock()
|
||||
|
||||
var devices, jidsToSync []types.JID
|
||||
var devices, jidsToSync, fbJIDsToSync []types.JID
|
||||
for _, jid := range jids {
|
||||
cached, ok := cli.userDevicesCache[jid]
|
||||
if ok && len(cached) > 0 {
|
||||
devices = append(devices, cached...)
|
||||
if ok && len(cached.devices) > 0 {
|
||||
devices = append(devices, cached.devices...)
|
||||
} else if jid.Server == types.MessengerServer {
|
||||
fbJIDsToSync = append(fbJIDsToSync, jid)
|
||||
} else {
|
||||
jidsToSync = append(jidsToSync, jid)
|
||||
}
|
||||
}
|
||||
if len(jidsToSync) == 0 {
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
list, err := cli.usync(ctx, jidsToSync, "query", "message", []waBinary.Node{
|
||||
{Tag: "devices", Attrs: waBinary.Attrs{"version": "2"}},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, user := range list.GetChildren() {
|
||||
jid, jidOK := user.Attrs["jid"].(types.JID)
|
||||
if user.Tag != "user" || !jidOK {
|
||||
continue
|
||||
if len(jidsToSync) > 0 {
|
||||
list, err := cli.usync(ctx, jidsToSync, "query", "message", []waBinary.Node{
|
||||
{Tag: "devices", Attrs: waBinary.Attrs{"version": "2"}},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, user := range list.GetChildren() {
|
||||
jid, jidOK := user.Attrs["jid"].(types.JID)
|
||||
if user.Tag != "user" || !jidOK {
|
||||
continue
|
||||
}
|
||||
userDevices := parseDeviceList(jid.User, user.GetChildByTag("devices"))
|
||||
cli.userDevicesCache[jid] = deviceCache{devices: userDevices, dhash: participantListHashV2(userDevices)}
|
||||
devices = append(devices, userDevices...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(fbJIDsToSync) > 0 {
|
||||
list, err := cli.getFBIDDevices(ctx, fbJIDsToSync)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, user := range list.GetChildren() {
|
||||
jid, jidOK := user.Attrs["jid"].(types.JID)
|
||||
if user.Tag != "user" || !jidOK {
|
||||
continue
|
||||
}
|
||||
userDevices := parseFBDeviceList(jid, user.GetChildByTag("devices"))
|
||||
cli.userDevicesCache[jid] = userDevices
|
||||
devices = append(devices, userDevices.devices...)
|
||||
}
|
||||
userDevices := parseDeviceList(jid.User, user.GetChildByTag("devices"))
|
||||
cli.userDevicesCache[jid] = userDevices
|
||||
devices = append(devices, userDevices...)
|
||||
}
|
||||
|
||||
return devices, nil
|
||||
@ -472,13 +574,56 @@ func parseDeviceList(user string, deviceNode waBinary.Node) []types.JID {
|
||||
return devices
|
||||
}
|
||||
|
||||
func parseFBDeviceList(user types.JID, deviceList waBinary.Node) deviceCache {
|
||||
children := deviceList.GetChildren()
|
||||
devices := make([]types.JID, 0, len(children))
|
||||
for _, device := range children {
|
||||
deviceID, ok := device.AttrGetter().GetInt64("id", true)
|
||||
if device.Tag != "device" || !ok {
|
||||
continue
|
||||
}
|
||||
user.Device = uint16(deviceID)
|
||||
devices = append(devices, user)
|
||||
// TODO take identities here too?
|
||||
}
|
||||
// TODO do something with the icdc blob?
|
||||
return deviceCache{
|
||||
devices: devices,
|
||||
dhash: deviceList.AttrGetter().String("dhash"),
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) getFBIDDevices(ctx context.Context, jids []types.JID) (*waBinary.Node, error) {
|
||||
users := make([]waBinary.Node, len(jids))
|
||||
for i, jid := range jids {
|
||||
users[i].Tag = "user"
|
||||
users[i].Attrs = waBinary.Attrs{"jid": jid}
|
||||
// TODO include dhash for users
|
||||
}
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Context: ctx,
|
||||
Namespace: "fbid:devices",
|
||||
Type: iqGet,
|
||||
To: types.ServerJID,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "users",
|
||||
Content: users,
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send usync query: %w", err)
|
||||
} else if list, ok := resp.GetOptionalChildByTag("users"); !ok {
|
||||
return nil, &ElementMissingError{Tag: "users", In: "response to fbid devices query"}
|
||||
} else {
|
||||
return &list, err
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) usync(ctx context.Context, jids []types.JID, mode, context string, query []waBinary.Node) (*waBinary.Node, error) {
|
||||
userList := make([]waBinary.Node, len(jids))
|
||||
for i, jid := range jids {
|
||||
userList[i].Tag = "user"
|
||||
if jid.AD {
|
||||
jid.AD = false
|
||||
}
|
||||
jid = jid.ToNonAD()
|
||||
switch jid.Server {
|
||||
case types.LegacyUserServer:
|
||||
userList[i].Content = []waBinary.Node{{
|
||||
@ -519,3 +664,58 @@ func (cli *Client) usync(ctx context.Context, jids []types.JID, mode, context st
|
||||
return &list, err
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) parseBlocklist(node *waBinary.Node) *types.Blocklist {
|
||||
output := &types.Blocklist{
|
||||
DHash: node.AttrGetter().String("dhash"),
|
||||
}
|
||||
for _, child := range node.GetChildren() {
|
||||
ag := child.AttrGetter()
|
||||
blockedJID := ag.JID("jid")
|
||||
if !ag.OK() {
|
||||
cli.Log.Debugf("Ignoring contact blocked data with unexpected attributes: %v", ag.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
output.JIDs = append(output.JIDs, blockedJID)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// GetBlocklist gets the list of users that this user has blocked.
|
||||
func (cli *Client) GetBlocklist() (*types.Blocklist, error) {
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Namespace: "blocklist",
|
||||
Type: iqGet,
|
||||
To: types.ServerJID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list, ok := resp.GetOptionalChildByTag("list")
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: "list", In: "response to blocklist query"}
|
||||
}
|
||||
return cli.parseBlocklist(&list), nil
|
||||
}
|
||||
|
||||
// UpdateBlocklist updates the user's block list and returns the updated list.
|
||||
func (cli *Client) UpdateBlocklist(jid types.JID, action events.BlocklistChangeAction) (*types.Blocklist, error) {
|
||||
resp, err := cli.sendIQ(infoQuery{
|
||||
Namespace: "blocklist",
|
||||
Type: iqSet,
|
||||
To: types.ServerJID,
|
||||
Content: []waBinary.Node{{
|
||||
Tag: "item",
|
||||
Attrs: waBinary.Attrs{
|
||||
"jid": jid,
|
||||
"action": string(action),
|
||||
},
|
||||
}},
|
||||
})
|
||||
list, ok := resp.GetOptionalChildByTag("list")
|
||||
if !ok {
|
||||
return nil, &ElementMissingError{Tag: "list", In: "response to blocklist update"}
|
||||
}
|
||||
return cli.parseBlocklist(&list), err
|
||||
}
|
||||
|
25
vendor/go.mau.fi/whatsmeow/util/cbcutil/cbc_test.go
vendored
Normal file
25
vendor/go.mau.fi/whatsmeow/util/cbcutil/cbc_test.go
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
package cbcutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
key := []byte("MySecretSecretSecretSecretKey123")
|
||||
plain := []byte("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
|
||||
|
||||
cipher, err := Encrypt(key, nil, plain)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
p, err := Decrypt(key, nil, cipher)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !bytes.Equal(plain, p) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
@ -9,9 +9,8 @@ package keys
|
||||
|
||||
import (
|
||||
"go.mau.fi/libsignal/ecc"
|
||||
"go.mau.fi/util/random"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
|
||||
"go.mau.fi/whatsmeow/util/randbytes"
|
||||
)
|
||||
|
||||
type KeyPair struct {
|
||||
@ -31,7 +30,7 @@ func NewKeyPairFromPrivateKey(priv [32]byte) *KeyPair {
|
||||
}
|
||||
|
||||
func NewKeyPair() *KeyPair {
|
||||
priv := *(*[32]byte)(randbytes.Make(32))
|
||||
priv := *(*[32]byte)(random.Bytes(32))
|
||||
|
||||
priv[0] &= 248
|
||||
priv[31] &= 127
|
||||
|
38
vendor/go.mau.fi/whatsmeow/util/log/zerolog.go
vendored
Normal file
38
vendor/go.mau.fi/whatsmeow/util/log/zerolog.go
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2024 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 waLog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type zeroLogger struct {
|
||||
mod string
|
||||
zerolog.Logger
|
||||
}
|
||||
|
||||
// Zerolog wraps a [zerolog.Logger] to implement the [Logger] interface.
|
||||
//
|
||||
// Subloggers will be created by setting the `sublogger` field in the log context.
|
||||
func Zerolog(log zerolog.Logger) Logger {
|
||||
return &zeroLogger{Logger: log}
|
||||
}
|
||||
|
||||
func (z *zeroLogger) Warnf(msg string, args ...any) { z.Warn().Msgf(msg, args...) }
|
||||
func (z *zeroLogger) Errorf(msg string, args ...any) { z.Error().Msgf(msg, args...) }
|
||||
func (z *zeroLogger) Infof(msg string, args ...any) { z.Info().Msgf(msg, args...) }
|
||||
func (z *zeroLogger) Debugf(msg string, args ...any) { z.Debug().Msgf(msg, args...) }
|
||||
func (z *zeroLogger) Sub(module string) Logger {
|
||||
if z.mod != "" {
|
||||
module = fmt.Sprintf("%s/%s", z.mod, module)
|
||||
}
|
||||
return &zeroLogger{mod: module, Logger: z.Logger.With().Str("sublogger", module).Logger()}
|
||||
}
|
||||
|
||||
var _ Logger = &zeroLogger{}
|
Loading…
Reference in New Issue
Block a user