I had to pause my dev for a few months. My Letsencrypt certificate expired in the meantime and there some changes in the libs.
I deleted my Letsencrypt directory (the one whith the certificates inside).
I am using greenlock-express API
Now,I cannot manage to pass the http-01 challenge when obtaining the certificate.
I have no problem to curl the file :
http://myserver.com/.well-known/acme-challenge/hRsScb0ZHcFyaroe73h2lnFcQfCTeDwFhVB8PtKHfYs
But I get errors when running my app :
ERROR in le-sni-auto:
Error: The CA was unable to validate the file you provisioned.
Fetching http://myserver.com/.well-known/acme-challenge/hRsScb0ZHcFyaroe73h2lnFcQfCTeDwFhVB8PtKHfYs: Timeout
I cannot firgure out whet is happenning...
Any idea ?
Edit 170912 - Configuration details
var lex = require('greenlock-express').create({
server: 'staging'
,challenges: {'http-01': require('le-challenge-fs').create({ webrootPath: './letsencrypt/tmp' })}
,store: require('le-store-certbot').create({
configDir: './letsencrypt'
,privkeyPath: ':configDir/live/:hostname/privkey.pem'
,fullchainPath: ':configDir/live/:hostname/fullchain.pem'
,certPath: ':configDir/live/:hostname/cert.pem'
,chainPath: ':configDir/live/:hostname/chain.pem'
,webrootPath: ':configDir/tmp'
,debug: false
})
,approveDomains: approveDomains
});
function approveDomains(opts, certs, cb) {
if (certs) {
opts.domains = certs.altnames;
}
else {
opts.email = 'contact#myserver.com';
opts.agreeTos = true;
opts.domains = [ 'myserver.com'];
}
cb(null, { options: opts, certs: certs });
}
http.createServer(lex.middleware(require('redirect-https')())).listen(80, _ => {
console.log("Listening for ACME http-01 challenges on", this.address());
});
https.createServer(lex.httpsOptions, lex.middleware(app)).listen(443, function () {
console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address());
});
Related
The API is written in NodeJS
Currently,
The app is capable of send a push notification in Apple's development environment using the code below.
Getting a BadDeviceToken 400 Error
Also, note development notifications were working (SO will not format my code below):
module.exports.sendNotification = (deviceToken, msg, payload) => {
const jwt = require("jsonwebtoken");
const http2 = require("http2");
const fs = require("fs");
const key = fs.readFileSync(process.env.APNS_KEY, "utf8");
// "iat" should not be older than 1 hr from current time or will get rejected
const token = jwt.sign(
{
iss: process.env.APNS_TEAM_ID, // "team ID" of your developer account
iat: Date.now() / 1000 // Replace with current unix epoch time
},
key,
{
header: {
alg: "ES256",
kid: process.env.APNS_KEY_ID // issuer key which is "key ID" of your p8 file
}
}
);
/*
Use 'https://api.production.push.apple.com' for production build
*/
const host = process.env.APNS_HOST;
const path = `/3/device/${deviceToken}`;
const client = http2.connect(host);
client.on("error", (err) => console.error(err));
const body = {
aps: {
alert: msg,
"content-available": 1,
payload
}
};
const headers = {
":method": "POST",
"apns-topic": process.env.APNS_TOPIC, // your application bundle ID
":scheme": "https",
":path": path,
authorization: `bearer ${token}`
};
const request = client.request(headers);
request.on("response", (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
return {
headers
}
});
request.setEncoding("utf8");
let data = "";
request.on("data", (chunk) => { data += chunk; });
request.write(JSON.stringify(body));
request.on("end", () => {
console.log(`\n${data}`);
client.close();
});
request.end();
};
The desired outcome is to send a push notification using Apple's production APNS environment. My best try at solving this has been swapping the development url for the production, that returns a, "{"reason":"BadDeviceToken"} :status: 400 apns-id: "
Tries so far...
Here are the hosts I'm using:
Production = "https://api.push.apple.com" also tried "https://api.push.apple.com:443"
Development = "https://api.sandbox.push.apple.com"
Other things I've tried:
Certificates instead of tokens; not sure if I'm doing it right. So if you know, please drop the code it.
ChatGPT's sol'n:
const apn = require('apn');
// Path to the certificate file and passphrase (if any) const cert = '/path/to/cert.pem'; const key = '/path/to/key.pem'; const passphrase = 'your_certificate_passphrase';
// Create the APN provider with the certificate and key const provider = new apn.Provider({ cert: cert, key: key, passphrase: passphrase, production: true // set to false for development environment });
// Create the notification payload const payload = new apn.Payload({ alert: 'Hello World!', sound: 'default', badge: 1 });
// Send the notification to a device token const deviceToken = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; const note = new apn.Notification(); note.expiry = Math.floor(Date.now() / 1000) + 3600; note.payload = payload; note.topic = 'com.example.myapp'; provider.send(note, deviceToken).then(result => { console.log(result); });
I'm not sure where to find the passphrase for above, so I just removed it. The key, I found in the .pem file and just cut and pasted it out of that from the key beginning and end and replaced the old .p8 file text with it.
Also tried, SO answers: How do I switch the certificate from development to production?
Also tried, SO answers: iOS push notification device token for development and production
Also tried, iOS APNS Development [sandbox] vs Production
Also tried, changing the environment under the 'APS Environment' key in the Entitlements File from 'development' to 'production' and then generated a new device token.
When transitioning your APNS API/Backend Side Provider you need to construct the Provider like so...
const fs = require("fs");
const apn = require('apn');
// Create the APN provider with the certificate and key
const key = fs.readFileSync(process.env.APNS_KEY, "utf8");
const cert = fs.readFileSync(process.env.APNS_CERT, "utf8");
const provider = new apn.Provider({
token: {
cert: cert,
key: key,
teamId: process.env.APNS_TEAM_ID,
keyId: process.env.APNS_KEY_ID
},
production: true // set to false for development environment
});
Building the Provider, Cert and Key Look
Note that I'm using the cert from Developer portal AND the key to sign it. This is in the same section of the Apple Developer portal as the Development token (eg the .p8 file). These files (.pem and .p8) begin and end with, "-----BEGIN CERTIFICATE-----
", "-----END CERTIFICATE-----", "-----BEGIN PRIVATE KEY-----
", "-----END PRIVATE KEY-----". You will often see "token" in the instructions online, that is the object you pass into the Provider constructor as an arg. The token includes the cert and key, along with the other fields you see in the code.
NEXT, this took days for me to figure out. You cannot force the Simulator or side loading to create a production Device Token by changing the Entitlements File in XCode to, 'production' instead of 'development'. You MUST (as in there were no Push Notifications making it to my side loaded app through my API to APNS to my device, and I was getting "BadDeviceToken" instead) at least install the TestFlight version of your app in order to get a production Device Token. Once you have that you may pass it to your API, then use it send APNs to device(s).
Init Provider Options
You may also init your Provider like above instead of the "jwt" method. I've tried both and the above way seems the easiest and cleanest (less code).
WATCH OUT for tutorials that claim there is a way to determine between these two tokens, with "
const firstByte = parseInt(deviceToken.substr(0, 2), 16);
// Successfully determines the aps environment
const apsEnvironment = (firstByte & 0x80) ? 'production' : 'development';
"
Notification Content and Delivery
The following goes below the code snippet above...
const notification = new apn.Notification();
notification.alert = {
title: 'Hello World',
body: 'This is a test notification'
};
notification.topic = process.env.APNS_TOPIC;
console.log(`notification ${JSON.stringify(notification)}`)
provider.send(notification, deviceToken).then((result) => {
console.log(JSON.stringify(result));
});
This seems self exclamatory and did not hold me up. Also, there if you go to the definition of Notification, there is a payload attribute which you may define as other tutorials mentions.
Cheers! Happy Hacking!
I am trying to use #azure/msal-node on a node backend server.
all work fine for business accounts onmicrosoft.com but not for personnal accounts like outlook.com
according to this documentation, Authentication seems to be possible
https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth
But i don't understand if my problem come from azure AD configuration or from my code.
exp.post('/connect', function (req, res) {
let authCodeUrlParameters = {
scopes: SCOPES_OUTLOOK,
redirectUri: "http://localhost:4220/redirect",
};
publicMicrosoftClient.getAuthCodeUrl(authCodeUrlParameters).then((response) => {
if (req.body.email) {
response += `&login_hint=${req.body.email}`
}
open(response)
}).catch((error) => console.log(JSON.stringify(error)));
});
exp.get('/redirect', async function (req, res) {
try {
const form = {
'code': req.query.code,
'client_id': CLIENT_ID_OUTLOOK,
'scope': SCOPES_OUTLOOK.join(' '),
'redirect_uri': 'http://localhost:4220/redirect',
'grant_type': 'authorization_code',
'client_secret': encodeURI(SECRET_VALUE_OUTLOOK),
}
const options = {
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
method: 'post',
}
response = await got(options, { form });
respToken = response.body
...
} catch (error) {
console.log(error)
res.end();
}
});
the error come from ...v2.0/token request. the server response doesn't really help (error 400 bad request)
in azure AD we have app registered and all required scope with status granted.
Thank you in advance for your help,
Yan
• You are getting this error because you have not allowed or selected ‘Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)’ as shown below in the snapshot for the Azure AD app registered regarding authentication for your backend code: -
• Also, if you have already configured your Azure AD application registration for your node backend code, then you can also configure the above in your Azure AD app’s ‘Application Manifest’ by modifying the parameter ‘signInAudience’ with the value as ‘AzureADandPersonalMicrosoftAccount’ as well as ensure that the below parameters are also set as per the stated values to resolve this issue: -
“allowPublicClient” : true
“accesstokenAcceptedVersion” : 2
For more information regarding this, kindly refer to the below link: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/reference-app-manifest
I have an Electron app. Running fine.
I add the following function in to main.ts:
function MakeHTTPCall(url:string, id:string)
{
var request = require('request');
var options = {
'method': 'GET',
'url': url,
'headers': {
'Cookie': ''
}
};
options.headers["Cookie"] = 'ID=' + id;
request(options, function (error:any, response:any) {
if (error){
throw new Error(error);
}
var s = response;
})
}
This code currently lands on the "throw new Error" line. When I look at the error text it is:
code:'SELF_SIGNED_CERT_IN_CHAIN'
message:'self signed certificate in certificate chain'
stack:'Error: self signed certificate in certificate chain\n at TLS
After doing a web search I added this to my main.ts code:
app.on ("certificate-error", (event, webContents, url, error, cert, callback) => {
// Do some verification based on the URL to not allow potentially malicious certs:
if (url.startsWith ("https://yourdomain.tld")) {
// Hint: For more security, you may actually perform some checks against
// the passed certificate (parameter "cert") right here
event.preventDefault (); // Stop Chromium from rejecting the certificate
callback (true); // Trust this certificate
} else callback (false); // Let Chromium do its thing
});
But this code is never called.
How can I get it to fire? I just want to see if I can ignore the error and make the HTML call.
Thanks
I use the following two sdk to connect and interact with the local-network created by the extension.
package.json:
...
"fabric-ca-client": "^2.2.0",
"fabric-network": "^2.2.0",
...
What I did first was get the default wallets created here:
C:\Users\johnny.dacosta\.fabric-vscode\environments\chaincode-env
I copied it to my workspace and then added the `admin' identity to my wallets with the following function:
if(this.walletProxy == null){
//get wallet store
this.walletProxy = await createWalletProxy(this.configService.get('localnetwork.orgWalletPath'));
//build new identity
const certBasePath = joinPathFromCWD(this.configService.get('localnetwork.pathIdentityCert'));
const keyBasePath = joinPathFromCWD(this.configService.get('localnetwork.pathIdentityKey'));
const certFilename = getFilesFromPath(certBasePath)[0];
const keyFilename = getFilesFromPath(keyBasePath)[0];
if(!certFilename || !keyFilename){
throw new NotFoundException("certFilename or keyFilename not found");
}
const cert = readFileSyncUTF8(`${certBasePath}/${certFilename}`).toString();
const key = readFileSyncUTF8(`${keyBasePath}/${keyFilename}`).toString();
//add new identity
await this.walletProxy.addIdentity(this.configService.get('localnetwork.identity'), {
credentials: {
certificate: cert,
privateKey: key,
},
mspId: 'Org1MSP',
type: 'X.509',
})
}
//ENV
{
orgWalletPath: ["local-network", "wallets", "Org1", "admin", "user"],
pathIdentityCert: ["local-network", "wallets", "Org1", "admin", "signcerts"],
pathIdentityKey: ["local-network", "wallets", "Org1", "admin", "keystore"],
}
I manage to add the new identity admin:
{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICWTCCAf+gAwIBAgIUIcgD17E4QtTsYMfeUO9Gg4SdSyIwCgYIKoZIzj0EAwIw\nfzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xHzAdBgNVBAoTFkludGVybmV0IFdpZGdldHMsIEluYy4xDDAK\nBgNVBAsTA1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMjAwODEzMTIwNjAw\nWhcNMjEwODEzMTIxMTAwWjBdMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGgg\nQ2Fyb2xpbmExFDASBgNVBAoTC0h5cGVybGVkZ2VyMQ8wDQYDVQQLEwZjbGllbnQx\nDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfkO0UxnK\nfEKmESj0GxyjSh8ljFSgXOCFqINXo66hnBb8M5XQMNE4HJFrJ5Aa0bPfvlNjCLXp\nu4MGWN3mFf1qb6N7MHkwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFO/aOEcikRVj/j/coHPhFPS74x4WMB8GA1UdIwQYMBaAFBdnQj2qnoI/\nxMUdn1vDmdG1nEgQMBkGA1UdEQQSMBCCDmRvY2tlci1kZXNrdG9wMAoGCCqGSM49\nBAMCA0gAMEUCIQC/inkjTud4btEeECODuZQhEEZG0OgDDoSkfhNNJF82wgIgYYvF\nLK1NgJxMdYwxQYhGXSV568d+HJROXgb7+vsjd3g=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGRpFEGhHS95y2Fyr\nLk6s6gd0V5D61akQC4RkEC1xYzmhRANCAAR+Q7RTGcp8QqYRKPQbHKNKHyWMVKBc\n4IWog1ejrqGcFvwzldAw0TgckWsnkBrRs9++U2MItem7gwZY3eYV/Wpv\n-----END PRIVATE KEY-----\n"},"mspId":"Org1MSP","type":"X.509","version":1}
With this identity I can getState of my asset:
But if I try to do putState transaction I got this error:
2020-08-13T13:14:14.117Z - error: [DiscoveryHandler]: _build_endorse_group_member >> G1:0 - error on endorsement to peer0.org2.example.com:17097 error Error: Broadcast Client peer0.org2.example.com:17097 grpc://localhost:17097 is not connected
2020-08-13T13:14:14.118Z - error: [DiscoveryHandler]: _build_endorse_group_member >> G0:0 - error on endorsement to peer0.org1.example.com:17092 error Error: Broadcast Client peer0.org1.example.com:17092 grpc://localhost:17092 is not connected
[Nest] 22548 - 2020-08-13 3:14:14 PM [ExceptionsHandler] Cannot read property 'name' of undefined +747178ms
TypeError: Cannot read property 'name' of undefined
at newEndorsementError (C:\DEV\CIB\cib-ledger-api\node_modules\fabric-network\lib\transaction.js:33:36)
at getResponsePayload (C:\DEV\CIB\cib-ledger-api\node_modules\fabric-network\lib\transaction.js:17:23)
at Transaction.submit (C:\DEV\CIB\cib-ledger-api\node_modules\fabric-network\lib\transaction.js:214:28)
at process._tickCallback (internal/process/next_tick.js:68:7)
All the peer are up:
I'm just confused why is not working with putState transaction.
I already check my smartcontract is good I can manage to do putState operation with the extension:
Your Environment
IBM Blockchain Platform Extension Version: 1.0.36
Visual Studio Code version: 1.47.3
Environment name and version: Node.js v10.16.3, npm v6.14.7):
Operating System and version: Windows 10 Enterprise v1903
I got the problem...
Just before the transaction I disconnected from the network...
async submitTransaction(transactionConfig: ITransaction2HLF): Promise<void> {
console.log(transactionConfig.transactionName)
console.log(...transactionConfig.params)
await this.buildInstance(transactionConfig);
this.gateway.disconnect() // <-- ERROR
await this.contract.submitTransaction(transactionConfig.transactionName, ...transactionConfig.params);
this.gateway.disconnect()
}
I just removed the line and I downgrade the version 2.2 to 1.4.x due to the vscode extension ibm blockchain plateform requirements.
I am using https and in case of a self-signed certificate, I want to prompt the user if he wants to import the required certificate. (Practically the same thing browser does when loading page without trusted certificate)
I have found out that there is a function dialog.showCertificateTrustDialog([browserWindow, ]options, callback) in electron which works just fine. I wanted to use it in a case when a certificate-errorappears.
Something like this:
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
dialog.showCertificateTrustDialog({certificate:certificate, message: "some msg"},
() => {
if (was certificate ok) {
event.preventDefault();
callback(true);
}
else {
callback(false);
}
}
);
});
But I have no idea how to do the was certificate ok part
Is it possible? Or do I have to for example load the page again to show it? If I run the app when the certificate is already imported, it works just fine. Otherwise, I get only a blank window.
Any help is appreciated, thank you
Currently, I have decided to use the following solution but it seems to me more like a hack. I try to load the page again after calling the showCertificateTrustDialog function again but if the certificate-error is thrown again I ignore it. I am still open to other solutions since I don't like this one
let certificateErrorRetry = false;
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
certificateErrorRetry = !certificateErrorRetry;
if (certificateErrorRetry) {
const {dialog} = require('electron');
dialog.showCertificateTrustDialog({certificate: certificate, message: "some msg" }, () => {
myapp.win.loadURL(url);
});
}
else { show some error }
});