fix: Fix VCard and User Avatar queries being encrypted
This commit is contained in:
parent
298a8342b8
commit
09696c1c4d
@ -1,5 +1,4 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:moxxmpp/src/connection.dart';
|
import 'package:moxxmpp/src/connection.dart';
|
||||||
import 'package:moxxmpp/src/events.dart';
|
import 'package:moxxmpp/src/events.dart';
|
||||||
import 'package:moxxmpp/src/jid.dart';
|
import 'package:moxxmpp/src/jid.dart';
|
||||||
@ -11,7 +10,6 @@ import 'package:moxxmpp/src/stanza.dart';
|
|||||||
import 'package:moxxmpp/src/stringxml.dart';
|
import 'package:moxxmpp/src/stringxml.dart';
|
||||||
|
|
||||||
class XmppManagerAttributes {
|
class XmppManagerAttributes {
|
||||||
|
|
||||||
XmppManagerAttributes({
|
XmppManagerAttributes({
|
||||||
required this.sendStanza,
|
required this.sendStanza,
|
||||||
required this.sendNonza,
|
required this.sendNonza,
|
||||||
|
@ -289,7 +289,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a disco info query to the (full) jid [entity], optionally with node=[node].
|
/// Sends a disco info query to the (full) jid [entity], optionally with node=[node].
|
||||||
Future<Result<DiscoError, DiscoInfo>> discoInfoQuery(String entity, { String? node}) async {
|
Future<Result<DiscoError, DiscoInfo>> discoInfoQuery(String entity, { String? node, bool shouldEncrypt = true }) async {
|
||||||
final cacheKey = DiscoCacheKey(entity, node);
|
final cacheKey = DiscoCacheKey(entity, node);
|
||||||
DiscoInfo? info;
|
DiscoInfo? info;
|
||||||
Completer<Result<DiscoError, DiscoInfo>>? completer;
|
Completer<Result<DiscoError, DiscoInfo>>? completer;
|
||||||
@ -316,6 +316,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
|
|
||||||
final stanza = await getAttributes().sendStanza(
|
final stanza = await getAttributes().sendStanza(
|
||||||
buildDiscoInfoQueryStanza(entity, node),
|
buildDiscoInfoQueryStanza(entity, node),
|
||||||
|
encrypted: !shouldEncrypt,
|
||||||
);
|
);
|
||||||
final query = stanza.firstTag('query');
|
final query = stanza.firstTag('query');
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
@ -359,9 +360,12 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a disco items query to the (full) jid [entity], optionally with node=[node].
|
/// Sends a disco items query to the (full) jid [entity], optionally with node=[node].
|
||||||
Future<Result<DiscoError, List<DiscoItem>>> discoItemsQuery(String entity, { String? node }) async {
|
Future<Result<DiscoError, List<DiscoItem>>> discoItemsQuery(String entity, { String? node, bool shouldEncrypt = true }) async {
|
||||||
final stanza = await getAttributes()
|
final stanza = await getAttributes()
|
||||||
.sendStanza(buildDiscoItemsQueryStanza(entity, node: node)) as Stanza;
|
.sendStanza(
|
||||||
|
buildDiscoItemsQueryStanza(entity, node: node),
|
||||||
|
encrypted: !shouldEncrypt,
|
||||||
|
) as Stanza;
|
||||||
|
|
||||||
final query = stanza.firstTag('query');
|
final query = stanza.firstTag('query');
|
||||||
if (query == null) return Result(InvalidResponseDiscoError());
|
if (query == null) return Result(InvalidResponseDiscoError());
|
||||||
|
@ -7,15 +7,20 @@ import 'package:moxxmpp/src/managers/namespaces.dart';
|
|||||||
import 'package:moxxmpp/src/namespaces.dart';
|
import 'package:moxxmpp/src/namespaces.dart';
|
||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
import 'package:moxxmpp/src/stringxml.dart';
|
import 'package:moxxmpp/src/stringxml.dart';
|
||||||
|
import 'package:moxxmpp/src/types/result.dart';
|
||||||
|
|
||||||
|
abstract class VCardError {}
|
||||||
|
|
||||||
|
class UnknownVCardError extends VCardError {}
|
||||||
|
|
||||||
|
class InvalidVCardError extends VCardError {}
|
||||||
|
|
||||||
class VCardPhoto {
|
class VCardPhoto {
|
||||||
|
|
||||||
const VCardPhoto({ this.binval });
|
const VCardPhoto({ this.binval });
|
||||||
final String? binval;
|
final String? binval;
|
||||||
}
|
}
|
||||||
|
|
||||||
class VCard {
|
class VCard {
|
||||||
|
|
||||||
const VCard({ this.nickname, this.url, this.photo });
|
const VCard({ this.nickname, this.url, this.photo });
|
||||||
final String? nickname;
|
final String? nickname;
|
||||||
final String? url;
|
final String? url;
|
||||||
@ -23,7 +28,6 @@ class VCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class VCardManager extends XmppManagerBase {
|
class VCardManager extends XmppManagerBase {
|
||||||
|
|
||||||
VCardManager() : _lastHash = {}, super();
|
VCardManager() : _lastHash = {}, super();
|
||||||
final Map<String, String> _lastHash;
|
final Map<String, String> _lastHash;
|
||||||
|
|
||||||
@ -59,12 +63,18 @@ class VCardManager extends XmppManagerBase {
|
|||||||
final lastHash = _lastHash[from];
|
final lastHash = _lastHash[from];
|
||||||
if (lastHash != hash) {
|
if (lastHash != hash) {
|
||||||
_lastHash[from] = hash;
|
_lastHash[from] = hash;
|
||||||
final vcard = await requestVCard(from);
|
final vcardResult = await requestVCard(from);
|
||||||
|
|
||||||
if (vcard != null) {
|
if (vcardResult.isType<VCard>()) {
|
||||||
final binval = vcard.photo?.binval;
|
final binval = vcardResult.get<VCard>().photo?.binval;
|
||||||
if (binval != null) {
|
if (binval != null) {
|
||||||
getAttributes().sendEvent(AvatarUpdatedEvent(jid: from, base64: binval, hash: hash));
|
getAttributes().sendEvent(
|
||||||
|
AvatarUpdatedEvent(
|
||||||
|
jid: from,
|
||||||
|
base64: binval,
|
||||||
|
hash: hash,
|
||||||
|
),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
logger.warning('No avatar data found');
|
logger.warning('No avatar data found');
|
||||||
}
|
}
|
||||||
@ -95,7 +105,7 @@ class VCardManager extends XmppManagerBase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<VCard?> requestVCard(String jid) async {
|
Future<Result<VCardError, VCard>> requestVCard(String jid) async {
|
||||||
final result = await getAttributes().sendStanza(
|
final result = await getAttributes().sendStanza(
|
||||||
Stanza.iq(
|
Stanza.iq(
|
||||||
to: jid,
|
to: jid,
|
||||||
@ -107,12 +117,13 @@ class VCardManager extends XmppManagerBase {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
encrypted: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result.attributes['type'] != 'result') return null;
|
if (result.attributes['type'] != 'result') return Result(UnknownVCardError());
|
||||||
final vcard = result.firstTag('vCard', xmlns: vCardTempXmlns);
|
final vcard = result.firstTag('vCard', xmlns: vCardTempXmlns);
|
||||||
if (vcard == null) return null;
|
if (vcard == null) return Result(UnknownVCardError());
|
||||||
|
|
||||||
return _parseVCard(vcard);
|
return Result(_parseVCard(vcard));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,24 @@ import 'package:moxxmpp/src/managers/base.dart';
|
|||||||
import 'package:moxxmpp/src/managers/namespaces.dart';
|
import 'package:moxxmpp/src/managers/namespaces.dart';
|
||||||
import 'package:moxxmpp/src/namespaces.dart';
|
import 'package:moxxmpp/src/namespaces.dart';
|
||||||
import 'package:moxxmpp/src/stringxml.dart';
|
import 'package:moxxmpp/src/stringxml.dart';
|
||||||
|
import 'package:moxxmpp/src/types/result.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0030/errors.dart';
|
import 'package:moxxmpp/src/xeps/xep_0030/errors.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0030/types.dart';
|
import 'package:moxxmpp/src/xeps/xep_0030/types.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
|
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0060/errors.dart';
|
import 'package:moxxmpp/src/xeps/xep_0060/errors.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0060/xep_0060.dart';
|
import 'package:moxxmpp/src/xeps/xep_0060/xep_0060.dart';
|
||||||
|
|
||||||
class UserAvatar {
|
abstract class AvatarError {}
|
||||||
|
|
||||||
|
class UnknownAvatarError extends AvatarError {}
|
||||||
|
|
||||||
|
class UserAvatar {
|
||||||
const UserAvatar({ required this.base64, required this.hash });
|
const UserAvatar({ required this.base64, required this.hash });
|
||||||
final String base64;
|
final String base64;
|
||||||
final String hash;
|
final String hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserAvatarMetadata {
|
class UserAvatarMetadata {
|
||||||
|
|
||||||
const UserAvatarMetadata(
|
const UserAvatarMetadata(
|
||||||
this.id,
|
this.id,
|
||||||
this.length,
|
this.length,
|
||||||
@ -65,27 +68,27 @@ class UserAvatarManager extends XmppManagerBase {
|
|||||||
|
|
||||||
/// Requests the avatar from [jid]. Returns the avatar data if the request was
|
/// Requests the avatar from [jid]. Returns the avatar data if the request was
|
||||||
/// successful. Null otherwise
|
/// successful. Null otherwise
|
||||||
// TODO(Unknown): Migrate to Resultsv2
|
Future<Result<AvatarError, UserAvatar>> getUserAvatar(String jid) async {
|
||||||
Future<UserAvatar?> getUserAvatar(String jid) async {
|
|
||||||
final pubsub = _getPubSubManager();
|
final pubsub = _getPubSubManager();
|
||||||
final resultsRaw = await pubsub.getItems(jid, userAvatarDataXmlns);
|
final resultsRaw = await pubsub.getItems(jid, userAvatarDataXmlns);
|
||||||
if (resultsRaw.isType<PubSubError>()) return null;
|
if (resultsRaw.isType<PubSubError>()) return Result(UnknownAvatarError());
|
||||||
|
|
||||||
final results = resultsRaw.get<List<PubSubItem>>();
|
final results = resultsRaw.get<List<PubSubItem>>();
|
||||||
if (results.isEmpty) return null;
|
if (results.isEmpty) return Result(UnknownAvatarError());
|
||||||
|
|
||||||
final item = results[0];
|
final item = results[0];
|
||||||
return UserAvatar(
|
return Result(
|
||||||
base64: item.payload.innerText(),
|
UserAvatar(
|
||||||
hash: item.id,
|
base64: item.payload.innerText(),
|
||||||
|
hash: item.id,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Publish the avatar data, [base64], on the pubsub node using [hash] as
|
/// Publish the avatar data, [base64], on the pubsub node using [hash] as
|
||||||
/// the item id. [hash] must be the SHA-1 hash of the image data, while
|
/// the item id. [hash] must be the SHA-1 hash of the image data, while
|
||||||
/// [base64] must be the base64-encoded version of the image data.
|
/// [base64] must be the base64-encoded version of the image data.
|
||||||
// TODO(Unknown): Migrate to Resultsv2
|
Future<Result<AvatarError, bool>> publishUserAvatar(String base64, String hash, bool public) async {
|
||||||
Future<bool> publishUserAvatar(String base64, String hash, bool public) async {
|
|
||||||
final pubsub = _getPubSubManager();
|
final pubsub = _getPubSubManager();
|
||||||
final result = await pubsub.publish(
|
final result = await pubsub.publish(
|
||||||
getAttributes().getFullJID().toBare().toString(),
|
getAttributes().getFullJID().toBare().toString(),
|
||||||
@ -101,14 +104,15 @@ class UserAvatarManager extends XmppManagerBase {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return !result.isType<PubSubError>();
|
if (result.isType<PubSubError>()) return Result(UnknownAvatarError());
|
||||||
|
|
||||||
|
return const Result(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Publish avatar metadata [metadata] to the User Avatar's metadata node. If [public]
|
/// Publish avatar metadata [metadata] to the User Avatar's metadata node. If [public]
|
||||||
/// is true, then the node will be set to an 'open' access model. If [public] is false,
|
/// is true, then the node will be set to an 'open' access model. If [public] is false,
|
||||||
/// then the node will be set to an 'roster' access model.
|
/// then the node will be set to an 'roster' access model.
|
||||||
// TODO(Unknown): Migrate to Resultsv2
|
Future<Result<AvatarError, bool>> publishUserAvatarMetadata(UserAvatarMetadata metadata, bool public) async {
|
||||||
Future<bool> publishUserAvatarMetadata(UserAvatarMetadata metadata, bool public) async {
|
|
||||||
final pubsub = _getPubSubManager();
|
final pubsub = _getPubSubManager();
|
||||||
final result = await pubsub.publish(
|
final result = await pubsub.publish(
|
||||||
getAttributes().getFullJID().toBare().toString(),
|
getAttributes().getFullJID().toBare().toString(),
|
||||||
@ -135,39 +139,37 @@ class UserAvatarManager extends XmppManagerBase {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return result.isType<PubSubError>();
|
if (result.isType<PubSubError>()) return Result(UnknownAvatarError());
|
||||||
|
return const Result(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subscribe the data and metadata node of [jid].
|
/// Subscribe the data and metadata node of [jid].
|
||||||
// TODO(Unknown): Migrate to Resultsv2
|
Future<Result<AvatarError, bool>> subscribe(String jid) async {
|
||||||
Future<bool> subscribe(String jid) async {
|
|
||||||
await _getPubSubManager().subscribe(jid, userAvatarDataXmlns);
|
await _getPubSubManager().subscribe(jid, userAvatarDataXmlns);
|
||||||
await _getPubSubManager().subscribe(jid, userAvatarMetadataXmlns);
|
await _getPubSubManager().subscribe(jid, userAvatarMetadataXmlns);
|
||||||
|
|
||||||
return true;
|
return const Result(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unsubscribe the data and metadata node of [jid].
|
/// Unsubscribe the data and metadata node of [jid].
|
||||||
// TODO(Unknown): Migrate to Resultsv2
|
Future<Result<AvatarError, bool>> unsubscribe(String jid) async {
|
||||||
Future<bool> unsubscribe(String jid) async {
|
|
||||||
await _getPubSubManager().unsubscribe(jid, userAvatarDataXmlns);
|
await _getPubSubManager().unsubscribe(jid, userAvatarDataXmlns);
|
||||||
await _getPubSubManager().subscribe(jid, userAvatarMetadataXmlns);
|
await _getPubSubManager().subscribe(jid, userAvatarMetadataXmlns);
|
||||||
|
|
||||||
return true;
|
return const Result(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the PubSub Id of an avatar after doing a disco#items query.
|
/// Returns the PubSub Id of an avatar after doing a disco#items query.
|
||||||
/// Note that this assumes that there is only one (1) item published on
|
/// Note that this assumes that there is only one (1) item published on
|
||||||
/// the node.
|
/// the node.
|
||||||
// TODO(Unknown): Migrate to Resultsv2
|
Future<Result<AvatarError, String>> getAvatarId(String jid) async {
|
||||||
Future<String?> getAvatarId(String jid) async {
|
|
||||||
final disco = getAttributes().getManagerById(discoManager)! as DiscoManager;
|
final disco = getAttributes().getManagerById(discoManager)! as DiscoManager;
|
||||||
final response = await disco.discoItemsQuery(jid, node: userAvatarDataXmlns);
|
final response = await disco.discoItemsQuery(jid, node: userAvatarDataXmlns, shouldEncrypt: false);
|
||||||
if (response.isType<DiscoError>()) return null;
|
if (response.isType<DiscoError>()) return Result(UnknownAvatarError());
|
||||||
|
|
||||||
final items = response.get<List<DiscoItem>>();
|
final items = response.get<List<DiscoItem>>();
|
||||||
if (items.isEmpty) return null;
|
if (items.isEmpty) return Result(UnknownAvatarError());
|
||||||
|
|
||||||
return items.first.name;
|
return Result(items.first.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user