I am successfully receiving push notifications with service account for a gmail user (impersonate) following official documentation.
But when calling watch I would like to be notified only when new messages arrive, not when any change happens. (For example: message read, message deleted ...)
I try filtering by INBOX and UNREAD, but I get notification even when messages is marked as read.
My code:
this._service.Users.Watch(new WatchRequest
{
TopicName = "projects/my-project-id/topics/gmail",
LabelFilterAction = "include",
//LabelIds = new [] { "UNREAD" }
LabelIds = new[] { "INBOX" }
}, "me").Execute();
Is it possible to receive notification only when new message arrives?
And here is code for subscribing:
var projectId = "my-project-id";
var topicId = "gmail";
var subscriptionId = "unread-gmail";
TopicName topicName = new TopicName(projectId, topicId);
SubscriptionName subscriptionName = new SubscriptionName(projectId, subscriptionId);
PublisherClient publisher = await PublisherClient.CreateAsync(topicName);
SubscriberClient subscriber = await SubscriberClient.CreateAsync(subscriptionName);
await subscriber.StartAsync((msg, cancellationToken) =>
{
Console.WriteLine($"Received message {msg.MessageId} published at {msg.PublishTime.ToDateTime()}");
Console.WriteLine($"Text: '{msg.Data.ToStringUtf8()}'");
return Task.FromResult(SubscriberClient.Reply.Ack);
});
Related
How do I send a Security Sign-in mail to the users using firebase?
For example, your account was accessed at 3:21 pm, 16th Dec 2021.
Platform : Mac OS X, Chrome 96.0.4664
IP address: xxxxxxxxxxx
Location: xyz.
Thanks in advance.
Firebase doesn't have any feature built in for sending such sign-in alerts. It doesn't even have a way to build it on top of its existing providers, as there no server-side event when a user signs in.
The only option I can think of to implement this within Firebase is to implement your own custom sign-in provider, and then send a message from there.
It also sounds like an interesting feature, so I recommend you file a feature request for it.
I have come up with an implementation.
I don't know if it is wise to execute this client-side (Can also be done using Cloud Functions).
authResult = await auth.signInWithEmailAndPassword(
email: email,
password: password,
);
final Map<String, dynamic> device = await getDeviceInfo();
final Map<String, dynamic> net = await getNetworkInfo();
final DateTime time = DateTime.now();
//I am using Trigger Email Extension here.
await mail.doc().set({
'to': email.toLowerCase(),
'message': {
'subject': 'Succesful Login',
'text':
"Welcome back! You have successfully logged in to XYZ. You can now start using the app. Email = $email Platform: ${device["name"]} Time: $time IP Address: ${net["wifiIP"]}",
},
});
These are the functions mentioned above:
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:network_info_plus/network_info_plus.dart';
Future<Map<String, dynamic>> getDeviceInfo() async {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if (Platform.isIOS) {
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
return iosInfo.toMap();
} else if (Platform.isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
return androidInfo.toMap();
} else {
WebBrowserInfo webBrowserInfo = await deviceInfo.webBrowserInfo;
return webBrowserInfo.toMap();
}
}
Future<Map<String, dynamic>> getNetworkInfo() async {
final info = NetworkInfo();
var wifiName = await info.getWifiName(); // FooNetwork
var wifiBSSID = await info.getWifiBSSID(); // 11:22:33:44:55:66
var wifiIP = await info.getWifiIP(); // 192.168.1.43
var wifiIPv6 =
await info.getWifiIPv6(); // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
var wifiSubmask = await info.getWifiSubmask(); // 255.255.255.0
var wifiBroadcast = await info.getWifiBroadcast(); // 192.168.1.255
var wifiGateway = await info.getWifiGatewayIP(); // 192.168.1.1
return {
'wifiName': wifiName,
'wifiBSSID': wifiBSSID,
'wifiIP': wifiIP,
'wifiIPv6': wifiIPv6,
'wifiSubmask': wifiSubmask,
'wifiBroadcast': wifiBroadcast,
'wifiGateway': wifiGateway,
};
}
Trigger Email
Dart implementation of https://firebase.google.com/docs/firestore/solutions/presence
class RealtimeDatabase {
final FirebaseDatabase db = FirebaseDatabase.instance;
final AuthService authService = locator<AuthService>();
Future<void> connect() async {
// Fetch current user's ID from authentication service
User user = authService.currentUser;
String uid = user.uid;
// Create reference to this user's specific status node
// This is where we will store data about being online/offline
var userStatusRef = db.reference().child('/status/' + uid);
// We'll create two constants which we will write to the
// Realtime database when this device is offline or online
var isOfflineForDatabase = {
'state': 'offline',
'last_changed': ServerValue.timestamp,
};
var isOnlineForDatabase = {
'state': 'online',
'last_changed': ServerValue.timestamp,
};
// db.goOnline();
// Create a ref to '.info/connected' path in Realtime db
// This path returns true when connected and false when disconnected
db
.reference()
.child('.info/connected')
.onDisconnect()
.set(isOfflineForDatabase)
.then((_) => userStatusRef.set(isOnlineForDatabase));
}
}
We get the following error: Invalid write location: /.info/connected
E/MethodChannel#plugins.flutter.io/firebase_database(17220): Failed to handle method call
E/MethodChannel#plugins.flutter.io/firebase_database(17220): com.google.firebase.database.DatabaseException: Invalid write location: /.info/connected
E/MethodChannel#plugins.flutter.io/firebase_database(17220): at com.google.firebase.database.core.utilities.Validation.validateWritablePath(com.google.firebase:firebase-database##17.0.0:127)
E/MethodChannel#plugins.flutter.io/firebase_database(17220): at com.google.firebase.database.DatabaseReference.onDisconnect(com.google.firebase:firebase-database##17.0.0:475)
E/MethodChannel#plugins.flutter.io/firebase_database(17220): at io.flutter.plugins.firebase.database.MethodCallHandlerImpl.onMethodCall(MethodCallHandlerImpl.java:466)
...
What could be the source of the problem?
I will answer this for the search engines in the future.
Future<void> connect() async {
// Fetch current user's ID from authentication service
User user = authService.currentUser;
String uid = user.uid;
// Create reference to this user's specific status node
// This is where we will store data about being online/offline
var userStatusRef = db.reference().child('/status/' + uid);
// We'll create two constants which we will write to the
// Realtime database when this device is offline or online
var isOfflineForDatabase = {
'state': 'offline',
'last_changed': ServerValue.timestamp,
};
var isOnlineForDatabase = {
'state': 'online',
'last_changed': ServerValue.timestamp,
};
// This is the correct implementation
db.reference().child('.info/connected').onValue.listen((data) {
if (data.snapshot.value == false) {
return;
}
userStatusRef.onDisconnect().set(isOfflineForDatabase).then((_) {
userStatusRef.set(isOnlineForDatabase);
});
});
}
The user object has no photo_id, so is there way to get the user's avatar?
I didn't find any php code, but this nodejs snippet worked for me so I put this to give you the idea that how it works.
Create a bot(start chatting with #botfather in your telegram)
After creation of bot finished, it will give you a token for HTTP API
$ npm install --save node-telegram-bot-api
create a js file beside the node_modules folder(for example: server.js)
put this codes in the server.js file and then run it with $ node server.js
const TelegramBot = require('node-telegram-bot-api');
// replace the value below with the Telegram token you receive from #BotFather
const token = 'XXXX35XXXX:XXXX7DCYw5IsY6DHcwXXXXXXXXX';
// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token, {
polling: true
});
// Matches "/echo [whatever]"
bot.onText(/\/echo (.+)/, (msg, match) => {
// 'msg' is the received Message from Telegram
// 'match' is the result of executing the regexp above on the text content
// of the message
const chatId = msg.chat.id;
const resp = match[1]; // the captured "whatever"
// send back the matched "whatever" to the chat
bot.sendMessage(chatId, resp);
});
// Listen for any kind of message. There are different kinds of
// messages.
bot.on('message', (msg) => {
const chatId = msg.chat.id;
var user_profile = bot.getUserProfilePhotos(msg.from.id);
user_profile.then(function (res) {
var file_id = res.photos[0][0].file_id;
var file = bot.getFile(file_id);
file.then(function (result) {
var file_path = result.file_path;
var photo_url = `https://api.telegram.org/file/bot${token}/${file_path}`
bot.sendMessage(chatId, photo_url);
});
});
});
I have an index of notification ids associated with a user X. When I want to display these notifications I need to fetch them from the user X's notifications index which just contains the
a) id of the notification (nid)
b) status: "read/unread"
But I also need to go to
a) /notifcations/nid to get my notification data: text and fromUser
b) /users/fromUser to get the user data for that user
My question is about structure.
Did i structure my data properly and if so, how can I fetch all this information inside the Notification and when ready, present it to angular for displaying on the screen.
Here is my take on that below. Any critique (code/structure/anything) is welcome. Thanks.
P.S.
Also if I am replacing POJOs in firebaseArray with instances of Notification, how would that affect my DB when I say edit the notification and save it back to Firebase. How does AngularFire know what to save back?
/* Notifications */
.factory('Notifications', function(firebaseUrl, NotificationsFactory){
var ref = new Firebase(firebaseUrl);
return {
getNotificationsForUser : function(uid){
var userNotifRef = ref.child('users').child(uid).child('notifications');
return new NotificationsFactory(userNotifRef);
}
}
})
.factory('NotificationsFactory', function($firebaseArray, Notification) {
return $firebaseArray.extend({
$$added : function(snapshot, prevChild){ //called anytime a 'child_added' event occurs
return new Notification(snapshot);
}
})
})
.factory('Notification', function(firebaseUrl, $q, Users) {
var notifRef = (new Firebase(firebaseUrl)).child('notifications');
var usersRef = (new Firebase(firebaseUrl)).child('users');
var mainDeferred = $q.defer();
var notifDeferred = $q.defer();
var userDeferred = $q.defer();
var Notification = function(snapshot){
this.$id = snapshot.key();
this.status = snapshot.val().status;
this.message = null;
this.from = null;
this.to = null;
notifRef.child(this.$id).once('value', function(snap){ //change to on if expect notification to keep updating
var data = snap.val();
this.message = data.message;
this.from = data.from; //user id
this.to = data.to; //user id
notifDeferred.resolve();
});
notifDeferred.promise.then(function(){
this.from = Users.getUser(this.from);
this.to = Users.getUser(this.to);
this.from.$loaded().then(function(){
this.to.$loaded().then(function(){
mainDeferred.resolve();
})
})
})
};
Notification.prototype.ready = function(){
return mainDeferred.promise;
}
return Notification;
})
I'm trying to implement following functionality:
User signs in into Live Id account from Windows Phone 8.1 (or Universal) app.
App accesses Web Api that I develop with ASP.NET Web Api 2
In this Web Api I need to authenticate the user.
Later, I want to authenticate same user in web app
Here is what I'm doing, and it doesn't work.
In my Windows Phone App:
var authClient = new LiveAuthClient("http://myservice.cloudapp.net");
LiveLoginResult result = await authClient.LoginAsync(new string[] { "wl.signin" });
if (result.Status == LiveConnectSessionStatus.Connected)
{
connected = true;
var identity = await ConnectToApi(result.Session.AuthenticationToken);
Debug.WriteLine(identity);
}
And then
private async Task<string> ConnectToApi(string token)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://myservice.cloudapp.net/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
// HTTP GET
HttpResponseMessage response = await client.GetAsync("api/values");
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
return result;
}
else
return response.ReasonPhrase;
}
}
And then in my web api I have following
public void ConfigureAuth(IAppBuilder app)
{
app.UseMicrosoftAccountAuthentication(
clientId: "my client id",
clientSecret: "my secret");
}
I registered http://myservice.cloudapp.net as redirect url.
The problem is authentication doesn't work, web api actions do not recognize the user.
I got it totally wrong. First, I actually need to use app.UseJwtBearerAuthentication method. The example was found here http://code.lawrab.com/2014/01/securing-webapi-with-live-id.html. But when I tried, I got this error in the output
IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause
)
This one took me a while to figure out, until I found this post: JwtSecurityTokenHandler 4.0.0 Breaking Changes?
Putting these things together, I got the solution that seems to work now in my testing environment:
public void ConfigureAuth(IAppBuilder app)
{
var sha256 = new SHA256Managed();
var sKey = "<Secret key>" + "JWTSig";
var secretBytes = new UTF8Encoding(true, true).GetBytes(sKey);
var signingKey = sha256.ComputeHash(secretBytes);
var securityKeyProvider = new SymmetricKeyIssuerSecurityTokenProvider("urn:windows:liveid", signingKey);
var securityKey = securityKeyProvider.SecurityTokens.First().SecurityKeys.First();
var jwtOptions = new JwtBearerAuthenticationOptions()
{
//AllowedAudiences = new[] { "<url>" },
//IssuerSecurityTokenProviders = new[]
//{
// new SymmetricKeyIssuerSecurityTokenProvider("urn:windows:liveid",signingKey)
//},
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
{
IssuerSigningKeyResolver = (token, securityToken, keyIdentifier, validationParameters) =>
{
return securityKey;
},
ValidAudience = "<url>",
ValidIssuer = securityKeyProvider.Issuer
}
};
app.UseJwtBearerAuthentication(jwtOptions);
}
For anybody looking to do this from JavaScript I managed to get this working by following steps from this blog. You can find the audience by putting your token through jwt.io
https://blog.dirk-eisenberg.de/2014/08/30/validate-authentication_token-from-microsoft-liveid-with-node-express-jwt/
const validateLiveJWT = (token) => {
const secret = '<<SECRET>>';
const sha256 = crypto.createHash('sha256');
sha256.update(secret + 'JWTSig', 'utf8');
const secretBase64 = sha256.digest('base64');
const secret = new Buffer(secretBase64, 'base64');
const options = {
audience: '<<AUDIENCE>>',
issuer: 'urn:windows:liveid',
};
return new Promise((resolve) => {
jwt.verify(token, secret, options, (err: any, claims: any) => {
if (err) {
resolve(undefined);
} else {
resolve(claims);
}
});
});
}