How can I test PushKit Voip? - push-notification

I created an app and added PushKit Voip. If I compile that and run from Xcode everything fine and I can receive pushes.
But if I install it from TestFlight, the pushes do not came.
Why? I send them the same way.

Once you receive silent push notification payload, then you have to schedule local notification because silent push notification does not come in notification center. upto your local notification sound file plays ( Max 30 seconds ) your application will be invoke in background or kill state. you can do require activity here but not UI activity.
While tapping on interactive local notification you can do further UI activity.
Use below structure to achieve your task.
Use this simplepush.php file
<?php
// Put your device token here (without spaces):
$deviceToken = '1234567890123456789';
//
// Put your private key's passphrase here:
$passphrase = 'ProjectName';
// Put your alert message here:
$message = 'My first push notification!';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'PemFileName.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
// 'ssl://gateway.push.apple.com:2195', $err,
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'content-available'=> 1,
'alert' => $message,
'sound' => 'default',
'badge' => 0,
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
// Close the connection to the server
fclose($fp);
Use below commands to create pem file and use it in above code
$ openssl x509 -in aps_development.cer -inform der -out PushCert.pem
# Convert .p12 to .pem. Enter your pass pharse which is the same pwd that you have given while creating the .p12 certificate. PEM pass phrase also same as .p12 cert.
$ openssl pkcs12 -nocerts -out PushKey1.pem -in pushkey.p12
Enter Import Password:
MAC verified OK
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
# To remove passpharse for the key to access globally. This only solved my stream_socket_client() & certificate capath warnings.
$ openssl rsa -in PushKey1.pem -out PushKey1_Rmv.pem
Enter pass phrase for PushChatKey1.pem:
writing RSA key
# To join the two .pem file into one file:
$ cat PushCert.pem PushKey1_Rmv.pem > ApnsDev.pem
After that go to simplepush.php location and fire command -> php simplepush.php
This way you can test your push kit notification setup architecture.
https://www.raywenderlich.com/123862/push-notifications-tutorial
Download
import UIKit
import PushKit
class AppDelegate: UIResponder, UIApplicationDelegate,PKPushRegistryDelegate{
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
application.registerForRemoteNotificationTypes(types)
pushKitRegistration()
return true
}
//MARK: - PushKitRegistration
func pushKitRegistration()
{
let mainQueue = dispatch_get_main_queue()
// Create a push registry object
if #available(iOS 8.0, *) {
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
// Set the registry's delegate to self
voipRegistry.delegate = self
// Set the push type to VoIP
voipRegistry.desiredPushTypes = [PKPushTypeVoIP]
} else {
// Fallback on earlier versions
}
}
#available(iOS 8.0, *)
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
// Register VoIP push token (a property of PKPushCredentials) with server
let hexString : String = UnsafeBufferPointer<UInt8>(start: UnsafePointer(credentials.token.bytes),
count: credentials.token.length).map { String(format: "%02x", $0) }.joinWithSeparator("")
print(hexString)
}
#available(iOS 8.0, *)
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
// Process the received push
// From here you have to schedule your local notification
}
}
In parallel if you setup Socket architecture. Then Socket used to broadcast data for example which users are online / offline and you need to know without calling an API then you can use socket, socket architecture on server will send data on online / offline user to devices without making request from device.

Related

Updating a WooCommerce order status based on a $GET response?

I tried to look things up but I am unable to find anything quite similar.
So I have an external file. That file uses $_GET in order to enable bidirectional text order confirmations.
I am trying to modify order status based on that specific $_GET response, but I am now unable to generate any sort of error in my error logs and cannot quite tell what I am doing wrong. Please bear with me as I am not very experience with this.
Here's what I have done so far:
<?php
define( 'WP_USE_THEMES', false );
require_once( $_SERVER[ 'DOCUMENT_ROOT' ] . '/wp-load.php' );
/*
Receiving SMS using 2-Way SMS & PHP
if ((isset($_GET["sender"])) and
(isset($_GET["receiver"])) and
(isset($_GET["message"])) and
(isset($_GET["timestamp"])) and
(isset($_GET["network_id"])) and
(isset($_GET["network_name"]))
)
{
/*
The Sender of the SMS (ie. 07xyzzzzzz)
*/
$sender = $_GET["sender"];
/*
The Shortcode on which the SMS was sent (ie. 17xy, 18xy, 37xy, 38xy etc.)
*/
$receiver = $_GET["receiver"];
/*
The Message sent by the Sender to the Shortcode
*/
$message = $_GET["message"];
/*
The Timestamp in which the Message was received on the Shortcode, in UNIX Timestamp format.
*/
$timestamp = $_GET["timestamp"];
/*
The Network ID in which the Sender is located, with the following possible values:
1 for Vodafone Romania
2 for Orange Romania
3 for Telekom Romania Mobile / Telekom Romania
5 for Digimobil (RCS-RDS)
*/
$network_id = $_GET["network_id"];
/*
The Network Name corresponding to the Network ID
*/
$network_name = $_GET["network_name"];
/*
Write the SMS received to a text file
Please note that this is for example purpose only and the file(s) below must be not be publicly accessible. If you will
choose to store the SMS received to file(s) you must enable access restrictions and deny access from public to the respective
file(s) and you must disable directory listing on the directory where the files are stored.
We recommend you storing the SMS received to a database.
$handler = fopen("sms-mobile-originated-".date("d-m-Y", $timestamp)."txt", "a+");
fwrite($handler,
"SMS Received: From ".$sender.", ".
"Receiver ".$receiver.", ".
"Network ID: ".$network_id.", ".
"Network Name: ".$network_name.", ".
"Date / Time: ".date("d-m-Y H:i:s", $timestamp).", ".
"Message: ".$message.
"\r\n"
);
fclose($handler);
/*
Return the response to the request
For each received SMS you may send a SMS response to the sender (mobile subscriber) using any of the following methods:
(1) Using SMSLink - SMS Gateway API, such as SMS Gateway (HTTP), SMS Gateway (SOAP), SMS Gateway (JSON) or SMS Gateway (BULK)
(2) Using the output of this script, by writing the desired response below, if you enable this coresponding option in 2-Way SMS,
2-Way SMS Campaigns - Settings. In this case the SMSLink will read the script output and will send an SMS to the sender with
the output text. Please note that the output should be plain text (you should not output any HTML code).
*/
function sms_confirmation(){
if (substr(trim(urldecode($message)), 0, strlen("CF ETIN")) == "CF ETIN")
{
global $woocommerce;
$order = new WC_Order($order_id);
$phone = $order->get_billing_phone();
if (((strlen($phone) == 10) and ($phone == $sender)) or
((strlen($phone) == 9) and ("0".$phone == $sender)) or
((strlen($phone) == 11) and ($phone == "4".$sender)) or
((strlen($phone) == 13) and ($phone == "004".$sender)) or
((strlen($phone) == 12) and ($phone == "+4".$sender))
)
{
$order->update_status('confirm-sms', __('Approved by the customer', 'woocommerce') );
}
}
};
echo "Message Successfuly Received."
}
else
{
echo "Invalid Request.";
}
?>

Authenticating Flask API with Wordpress

I have two websites, a Wordpress blog that hosts the majority of the content. I also have written an API with Flask. I would like to consume the API within Wordpress (a password-protected page), but I need to verify that the request is authenticated before responding from Flask.
How can I verify that there is a user logged in from Wordpress when I get a request to the Flask API?
You can implement an API Key Authentication (example in Flask: https://blog.teclado.com/api-key-authentication-with-flask/) or simply just use JWT.
For extra security, we can limit to accept request from certain domains like your Wordpress page, add expiration or allow to revoke a key.
I'm not clear whether you are communicating directly between WordPress and the Flask app (i.e. a server-to-server API) or whether you want the browser that is showing a WordPress page to then call an API hosted in the Flask app. If the former, then the API key method described by hungtran273 could work well for you.
This answer focuses on the latter (JS in the browser that proves the WordPress identity to the Flask app). This plugin uses a private key to produce a JWT for the user login. This avoids adding an API key per-user The Flask app can then use the associated public key to verify the JWT.
As written, this requires you put the private key in PEM format in the same directory as the plugin, which is not a good practice in production use.
rk_certinfo.php
<?php
/**
* Plugin Name: CertifiedUserInfo
* Plugin URI: https://ricardkelly.com/
* Description: Provides a JWT asserting the logged-in user to the site
* Version: 1.0.0
* Requires at least: 5.2
* Requires PHP: 7.2
* Author: Ricard Kelly
* Author URI: https://ricardkelly.com/
*/
function rk_certinfo_infoblock() {
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
$subject = $current_user->user_login;
$header = json_encode([
'typ' => 'JWT',
'alg' => 'RS256',
]);
$payload = json_encode([
'iss' => get_site_url(),
'sub' => $subject,
'iat' => time(),
'exp' => time() + (60*60*24),
]);
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
$base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
$data = $base64UrlHeader . "." . $base64UrlPayload;
$keyPrivatePath = plugin_dir_path( __FILE__ ) . 'private-key.pem';
$fp = fopen($keyPrivatePath,"r");
$privateKey = fread($fp,8192);
fclose($fp);
openssl_sign($data, $signature, $privateKey, OPENSSL_ALGO_SHA256);
$base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
$jwt = $data . "." . $base64UrlSignature;
echo "<script>\nfunction rk_certinfo() {\n";
echo " return \"" . $jwt . "\";\n";
echo "}\n";
echo "</script><!-- \n";
echo $payload;
echo "\n -->\n";
}
}
add_action( 'wp_footer', 'rk_certinfo_infoblock' );
?>
The code emits a script function that you can call from elsewhere in your page to get the JWT for passing to the Flask API. It also emits a comment that just gives you the signed info, which you would probably remove from the plugin after verifying it is producing the information you expect.
Here's a Flask app that consumes the JWT token in the Authorization header.
app.py
from flask import Flask, jsonify, request
from functools import wraps
import jwt
app = Flask(__name__)
public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKY5qH99Ouc/M/egCu6Z
ignTibNPXjNMOK2JYF00ytkfvafqMLuKrEjfExs6U+VQxqQQ4ZyzG/owaqht/zlR
aNhJMJOf0GA5EjtrT++uLh5k5MkA+hgWkRqIB869vctEpUSWzSOwOAR1OFoRXDAR
eESAw+LM4U/o9jq7A9IkgrgpoTC2F5th3ps4Sm7d2xiCLxyRWBmHHTYm7xaybOMe
xA7RzJCT04eUWwobYXdpvfhL8+izOuQlaA1+/dMCnaUWLModULgDlQFYDItULLNk
CF9UkrfpwYJUsO6oP/Ue7GvqtRHYkOfTh5GKtmB+pSlCuc+k+IPbeq6ljHFOLFTl
kQIDAQAB
-----END PUBLIC KEY-----
"""
def token_required(f):
#wraps(f)
def decorator(*args, **kwargs):
token = None
if 'Authorization' in request.headers:
token = request.headers['Authorization']
token = token.replace('Bearer','').strip()
if not token:
return jsonify({'message': 'a valid token is missing'})
try:
data = jwt.decode(token, public_key, algorithms=["RS256"])
current_user = data['sub']
except Exception as ex:
return jsonify({'message': 'token is invalid'})
return f(current_user, *args, **kwargs)
return decorator
#app.route('/api/<id_value>')
#token_required
def api_call(current_user, id_value):
return jsonify({'message': f'id provided was {id_value} by {current_user}'})
if __name__ == '__main__':
app.run(host='0.0.0.0', port='5000')

FTP_INCORRECT_HOST_KEY in N/SFTP Module

While creating the connection from NetSuite to SFTP using N/SFTP module i'm facing an error states:
"FTP_INCORRECT_HOST_KEY","message":"Provided host key does not match
remote server's fingerprint."
I have tried checking with my server team but no hope. Can any one suggest me how to resolve this or how can i get an authorized finger print host key from server.
I have tried with Suitescript 2.0 module (N/SFTP) with the help of the tool mentioned below.
https://ursuscode.com/netsuite-tips/suitescript-2-0-sftp-tool/
/**
*#NApiVersion 2.x
#NScriptType ScheduledScript
*/
define(['N/sftp', 'N/file', 'N/runtime'],function(sftp, file,runtime) {
function execute(context)
{
var myPwdGuid = "Encrypted password by GUID";
var myHostKey = "Some long Host key around 380 characters";
// establish connection to remote FTP server
var connection = sftp.createConnection({
username: 'fuel_integration',
passwordGuid: myPwdGuid, // references var myPwdGuid
url: '59.165.215.45',//Example IP
directory: '/sftproot/TaleoSync',
restrictToScriptIds : runtime.getCurrentScript().id,
restrictToCurrentUser :false,
hostKey: myHostKey // references var myHostKey
});
// specify the file to upload using the N/file module
// download the file from the remote server
var downloadedFile = connection.download({
directory: '/sftproot/TaleoSync',
filename: 'Fuel Funnel Report_without filter.csv'
});
downloadedFile.folder = ;
downloadedFile.save();
context.response.write(' Downloaded "Fuel Funnel Report_without filter" to fileCabinet');
}
return {
execute: execute
};
});
I expect to create a connection between SFTP and NetSuite to down a file from SFTP and place it to NetSuite file cabinet.
A couple of things:
restrictToScriptIds : runtime.getCurrentScript().id,
restrictToCurrentUser :false,
Are not part of the createConnection signature. Those should have been used when you created a Suitelet to vault your credential.
However the hostkey complaint may be dealt with by using ssh-keyscan from a linux box.
ssh-keyscan 59.165.215.45
should replay with the server name then ssh-rsa then a long base64 string. Copy that string so it ends up in myHostKey and set the hostKeyType to RSA.

PHPmailer - Add pdf file as attachment doesn't work

My Goal:
Use AddStringAttachment() to send a auto-generated base64 string as a .pdf file to another email address.
Coding Environment:
I'm working on WordPress with a ajax call passing a base64 string to the server. The size of the string is usually around 30kbs, it can be guaranteed not exceeding over 50kbs. I have MAX_EXECUTION_TIME 120s.
What I've Been Working Through:
I succeeded:
Sending plain text body
Sending a small .txt file
I failed:
Sending base64 string using AddStringAttachment(). The server returns me a 504 Gateway Time-out error most of time, even if $mail->send() function passes through, I can only receive a corrupt .pdf file with 10kbs bigger than original size.
Sending a already exist .pdf file with AddAttachment(), The server also returns me a 504 Gateway Time-out error, and I also get a warning like Resource interpreted as Document but transferred with MIME type application/pdf
My Code:
function sendPdf() {
$mail = new PHPMailer(true);
//Server settings
$mail->SMTPDebug = 2; // Enable verbose debug output
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = 'smtp.hostinger.com'; // Specify main and backup SMTP servers
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = 'janice#popper.ga'; // SMTP username
$mail->Password = 'secret'; // SMTP password
$mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted
$mail->Port = 587; // TCP port to connect to
//Recipient
$mail->SetFrom('janice#popper.ga');
$mail->AddAddress( 'xxxxxxxx#gmail.com' );
$pdf_base64 = $_POST[pdfString];
//Content
$mail->isHTML(true); // Set email format to HTML
$mail->Subject= ' New Application Form ';
$mail->Body= ' New Application Form From WordPress site ';
//Attachment
//$mail->AddStringAttachment($pdf_base64, $_POST[clientName].'_Application.pdf', 'base64', 'application/pdf');
//$mail->AddAttachment(dirname(__FILE__)."/Qian_Zhong_Application.pdf", 'Qian_Zhong_Application.pdf');
$error = '';
if(!$mail->send()){
$error = 'Mail error: '.$mail->ErrorInfo;
echo $error;
}else{
echo 'Message has been sent.';
}
exit; // This is required to end AJAX requests properly.
}
The data you pass in to addStringAttachment should be raw binary, not encoded in any way, as PHPMailer will take care of that for you. It will also set the encoding and MIME type from the filename you provide, so you do not need to set them manually.
Using a debugger would allow you to watch the script as it runs so you would be able to see exactly what it’s having trouble with. Any error 500s will cause errors to be logged in your web server logs and will usually provide more info.
I would also recommend against using $_POST[clientName] like that without any filtering or validation - you should never trust user input like that.

Why can't I collapse my push notifications when I use Firebase FCM?

const options = {
priority: 'high',
collapseKey: user_id
};
const deviceTokensPromise = db.ref('/users-fcm-tokens/' + user_id).once('value');
deviceTokensPromise.then(tokensSnapshot => {
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no device tokens to send to.');
}
const tokens = Object.keys(tokensSnapshot.val());
console.log(tokens);
console.log(payload);
return admin.messaging().sendToDevice(tokens, payload, options).then(response => {
console.log(response);
return removeInvalidFCMTokens(tokensSnapshot, response);
});
});
I have a collapse-Key field in my options.
When this code is ran, the iPhone receives multiple notifications, all on top of each other. I'd like to have most recent notification replace the previous ones.
#Timex you can pass same notification id for all notifications with the same collapse_id. For this you need to implement your own SendNotification method.
Check out the "Delivery Options" section in Firebase's FCM Messages documentation.
"collapsible" message behavior is supported on Android via FCM's collapse_key, on iOS via apns-collapse-id, and on JavaScript/Web via Topic.
Intuitively you might expect that the apns-collapse-id setting might go into the options parameter passed into the sendToMessage method you are using. However, this is not the case. Instead try patching it into the payload object, like this:
const patchedPayload = Object.assign({}, payload, {
apns: {
headers: {
'apns-collapse-id': user_id
}
}
});
This follows the payload format presented in the documentation linked above.
Once you've constructed this patched payload don't forget to update sendToDevice(tokens, payload, options) to sendToDevice(tokens, patchedPayload, options).
Hope this works out for you!
For iOS:
Use apns-collapse-id see the docs.
if you use collapsible messages, remember that FCM only allows a maximum of four different collapse keys to be used by the FCM connection server per registration token at any given time. You must not exceed this number, or it could cause unpredictable consequences.
Collapsible:
Use scenario
When there is a newer message that renders an older, related message irrelevant to the client app, FCM replaces the older message. For example: messages used to initiate a data sync from the server, or outdated notification messages.
How to send
Set the appropriate parameter in your message request:
collapseKey on Android
apns-collapse-id on iOS
Topic on Web
collapse_key in legacy protocols (all platforms)
See the implementation of apns-collapse-id in the article:
# Script to send push notifications for each song in a Phish Setlist via an updateable Push Notification.
# Place a config.yml in the same directory as the script and your push notification PEM file.
#
# Config Format:
# push_token: XXXXXXXXXXXXXX
# phish_api_key: XXXXXXXXXXXXXX
# push_mode: XXXXXXXXXXXXXX # development or production
require 'apnotic'
require 'phish_dot_net_client'
require 'awesome_print'
require 'yaml'
show_date = ARGV[0]
if show_date
script_config = YAML.load(File.read(File.expand_path('../config.yml', __FILE__)))
PhishDotNetClient.apikey = script_config["phish_api_key"]
the_show = PhishDotNetClient.shows_setlists_get :showdate => show_date
push_body = ""
if script_config["push_mode"] == "development"
connection = Apnotic::Connection.new(cert_path: "pushcert.pem", url: "https://api.development.push.apple.com:443")
else
connection = Apnotic::Connection.new(cert_path: "pushcert.pem")
end
token = script_config["push_token"]
notification = Apnotic::Notification.new(token)
notification.apns_id = SecureRandom.uuid
notification.apns_collapse_id = "Phish " + the_show[0]["showdate"] + ": "
notification.mutable_content = true
the_show[0]["setlistdata"].sets.each do |set_data|
set_name = set_data.name + ": "
set_data.songs.each do |song|
song_str = set_name + song.title
push_body = push_body + set_name + song.title + "\n"
set_name = ""
push_content = {'title' => song_str, 'body' => push_body}
puts push_content
notification.alert = push_content
response = connection.push(notification)
# read the response
puts ""
puts response.ok? # => true
puts response.status # => '200'
puts response.headers # => {":status"=>"200", "apns-id"=>"XXXX"}
puts response.body # => ""
puts ""
sleep(5)
end
end
connection.close
else
puts "Usage ruby send_push.rb SHOWDATE(Format:YYYY-MM-DD)"
end
For Android:
Use a tag variable in your notification payload.
"notification":{
"title":"Huawei",
"body":"21 Notification received",
"sound":"default",
"badge":4,
"tag":"1",
"click_action":"Your_Activity"
"icon":"Push_Icon"
}
I recommend using the latest send function from the firebase-admin, usage described here.

Resources