Prestashop (1.6.1.10) localization fail to Import a localization pack (Israel)
I get
[PrestaShopException]
Property Currency->decimals is not valid
at line 909 in file classes/ObjectModel.php
904. }
905.
906. $message = $this->validateField($field, $this->$field);
907. if ($message !== true) {
908. if ($die) {
909. throw new PrestaShopException($message);
910. }
911. return $error_return ? $message : false;
912. }
913. }
914.
ObjectModelCore->validateFields - [line 299 - classes/LocalizationPack.php]
LocalizationPackCore->_installCurrencies - [line 97 - classes/LocalizationPack.php] - [1 Arguments]
LocalizationPackCore->loadLocalisationPack - [line 203 - controllers/admin/AdminLocalizationController.php] - [4 Arguments]
AdminLocalizationControllerCore->postProcess - [line 178 - classes/controller/Controller.php]
ControllerCore->run - [line 367 - classes/Dispatcher.php]
DispatcherCore->dispatch - [line 58 - admin/index.p
This is used to work in the passed, I think something is broken in the language page
Here is how I by-pass the issue:
In the IMPORT A LOCALIZATION PACK form, uncheck Currency.
Import the pack, and create the currency manually.
Related
How can I validate an in-app purchase JWS Representation from StoreKit2 on my backend in Node?
Its easy enough to decode the payload, but I can't find public keys that Apple uses to sign these JWS/JWTs anywhere. Any other time I've worked with JWTs, you simply used the node jsonwebtoken library and passed in the signers public key or shared secret key, either configured or fetched from a JWK.
I can easily decode the JWS using node-jose j.JWS.createVerify().verify(jwsString, {allowEmbeddedKey: true}).then(r => obj = r) which gives me an object like:
{
protected: [ 'alg', 'x5c' ],
header: {
alg: 'ES256',
x5c: [
'MIIEMDueU3...',
'MII...,
'MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwSQXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0...'
]
},
payload: <Buffer 7b 22 74 72 61 6e 73 61 63 74 69 6f 6e 49 64 22 3a 22 31 30 30 30 30 30 30 38 38 36 39 31 32 38 39 30 22 2c 22 6f 72 69 67 69 6e 61 6c 54 72 61 6e 73 ... 420 more bytes>,
signature: <Buffer f8 85 65 79 a1 dc 74 dd 90 80 0a a4 08 85 30 e7 22 80 4c 20 66 09 0b 84 fc f4 e5 57 53 da d5 6f 13 c6 8f 56 e8 29 67 5c 95 a6 27 33 47 1e fe e9 6e 41 ... 14 more bytes>,
key: JWKBaseKeyObject {
keystore: JWKStore {},
length: 256,
kty: 'EC',
kid: 'Prod ECC Mac App Store and iTunes Store Receipt Signing',
use: '',
alg: ''
}
}
And its easy to JSON.parse the payload and get the data I want. But, how can i verify that its authentic using the certificate chain in the x5c field
Thank you!
Finally figured this out. It turns out that we needed a "hardcoded" certificate to check against.
Apple has the certificates needed on their website. You have download the root certificate (since that's the one signing the entire chain), but you can also get the intermediate one.
Once you download one you convert it to .pem:
$ openssl x509 -inform der -in apple_root.cer -out apple_root.pem
then all you need to do is verify them against the ones in the JWS (the following is in PHP, but you should get the gist):
if (openssl_x509_verify($jws_root_cert, $downloaded_apple_root_cert) == 1){
//valid
}
Hope this helps everyone else!
It is quite challenging to piece this together from all the information, but here's how to do this in NodeJS. Note that the latest Node supports built-in crypto, which makes it much much easier. Here's my code with the necessary comments.
const jwt = require('jsonwebtoken');
const fs = require('fs');
const {X509Certificate} = require('crypto');
async function decode(signedInfo) {
// MARK: - Creating certs using Node's new build-in crypto
function generateCertificate(cert) {
// MARK: - A simple function just like the PHP's chunk_split, used in generating pem.
function chunk_split(body, chunklen, end) {
chunklen = parseInt(chunklen, 10) || 76;
end = end || '\n';
if (chunklen < 1) {return false;}
return body.match(new RegExp(".{0," + chunklen + "}", "g")).join(end);
}
return new X509Certificate(`-----BEGIN CERTIFICATE-----\n${chunk_split(cert,64,'\n')}-----END CERTIFICATE-----`);
}
// MARK: - Removing the begin/end lines and all new lines/returns from pem file for comparison
function getPemContent(path) {
return fs.readFileSync(path)
.toString()
.replace('-----BEGIN CERTIFICATE-----', '')
.replace('-----END CERTIFICATE-----', '')
.replace(/[\n\r]+/g, '');
}
// MARK: - The signed info are in three parts as specified by Apple
const parts = signedInfo.split('.');
if (parts.length !== 3) {
console.log('The data structure is wrong! Check it! ');
return null;
}
// MARK: - All the information needed for verification is in the header
const header = JSON.parse(Buffer.from(parts[0], "base64").toString());
// MARK: - The chained certificates
const certificates = header.x5c.map(cert => generateCertificate(cert));
const chainLength = certificates.length;
// MARK: - Leaf certificate is the last one
const leafCert = header.x5c[chainLength-1];
// MARK: - Download .cer file at https://www.apple.com/certificateauthority/. Convert to pem file with this command line: openssl x509 -inform der -in AppleRootCA-G3.cer -out AppleRootCA-G3.pem
const AppleRootCA = getPemContent('AppleRootCA-G3.pem');
// MARK: - The leaf cert should be the same as the Apple root cert
const isLeafCertValid = AppleRootCA === leafCert;
if (!isLeafCertValid) {
console.log('Leaf cert not valid! ');
return null;
}
// MARK: If there are more than one certificates in the chain, we need to verify them one by one
if (chainLength > 1) {
for (var i=0; i < chainLength - 1; i++) {
const isCertValid = certificates[i].verify(certificates[i+1].publicKey);
if (!isCertValid) {
console.log(`Cert ${i} not valid! `);
return null;
}
}
}
return jwt.decode(signedInfo);
}
Good luck!
You need to validate the header and the payload with the sign like says in the WWDC videos:
https://developer.apple.com/videos/play/wwdc2022/10040/
https://developer.apple.com/videos/play/wwdc2021/10174/
But is more complicate than you think to do this if you don't have the knownledge about JWT because there is no documentation from Apple to do this, they only say to you "use your favorite cryptographic library to verify the data".
So after doing a lot of research, finally I found a solution using PHP 8.1 with Laravel.
First you need to install this library https://github.com/firebase/php-jwt:
composer require firebase/php-jwt
Then you need to implement the following method in order to validate the JWT from the transaction:
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
...
public function validateJwt($jwt)
{
$components = explode('.', $jwt);
if (count($components) !== 3) {
throw new \Exception('JWS string must contain 3 dot separated component.');
}
$header = base64_decode($components[0]);
$headerJson = json_decode($header,true);
$this->validateAppleRootCA($headerJson);
$jwsParsed = (array) $this->decodeCertificate($jwt, $headerJson, 0);
for ($i = 1; $i < count($headerJson) - 1; $i++) {
$this->decodeCertificate($jwt, $headerJson, $i);
}
// If the signature and the jws is invalid, it will thrown an exception
// If the signature and the jws is valid, it will create the $decoded object
// You can use the $decoded object as an array if you need:
$transactionId = $jwsParsed['transactionId'];
}
private function validateAppleRootCA($headerJson)
{
$lastIndex = array_key_last($headerJson['x5c']);
$certificate = $this->getCertificate($headerJson, $lastIndex);
// As Oliver Zhang says in their NodeJS example, download the .cer file at https://www.apple.com/certificateauthority/. Convert to pem file with this command line: openssl x509 -inform der -in AppleRootCA-G3.cer -out AppleRootCA-G3.pem
// In Laravel, this location is at storage/keys/AppleRootCA-G3.pem
$appleRootCA = file_get_contents(storage_path('keys/AppleRootCA-G3.pem'));
if ($certificate != $appleRootCA) {
throw new \Exception('jws invalid');
}
}
private function getCertificate($headerJson, $certificateIndex)
{
$certificate = '-----BEGIN CERTIFICATE-----'.PHP_EOL;
$certificate .= chunk_split($headerJson['x5c'][$certificateIndex],64,PHP_EOL);
$certificate .= '-----END CERTIFICATE-----'.PHP_EOL;
return $certificate;
}
private function decodeCertificate($jwt, $headerJson, $certificateIndex)
{
$certificate = $this->getCertificate($headerJson, 0);
$cert_object = openssl_x509_read($certificate);
$pkey_object = openssl_pkey_get_public($cert_object);
$pkey_array = openssl_pkey_get_details($pkey_object);
$publicKey = $pkey_array['key'];
$jwsParsed = null;
try {
$jwsDecoded = JWT::decode($jwt, new Key($publicKey, 'ES256'));
$jwsParsed = (array) $jwsDecoded;
} catch (SignatureInvalidException $e) {
throw new \Exception('signature invalid');
}
return $jwsParsed;
}
To call the function, you need to pass the jwt from the transaction:
$jwt = 'eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUl...';
validateJwt($jwt);
The JWS x5c header parameter contains the entire certificate chain used to sign and validate the JWS. There is no need to fetch any other certificates or keys.
The RFC specifies that the certificate corresponding to the public key that was used to sign the JWS must be the first certificate.
You can extract the public key from this certificate and use it to verify the JWS signature. There is some guidance on this in this answer
One of the great improvements in StoreKit2 is that you are no longer required to use a server to validate in app purchase transactions securely.
Apple's WWDC 2021 session on StoreKit2 describes the content of the JWS and also shows how to validate on device that the JWS was actually generated for that device.
But, what if you do want to validate the transaction on a server? Since the x5c claim contains the certificate chain, an attacker could sign a forged JWS with their own certificate and include that certificate in the x5c claim.
The answer is that you have your app send the original transaction id to your server along with any other information you need, such as the user's account identifier. Your server can then request the corresponding JWS from Apple and validate the signature of the returned JWS.
As the JWS was fetched from Apple by your server code it can be sure that it is not a spoofed JWS.
If possible, include an appAccountToken in your purchase request and either determine the expected token value based on the user's authentication to your server or (less effective) have your app supply the token when it supplies the original transaction id. You can then verify the token value in the JWS matches the expected value. This makes it harder for an attacker to replay some other purchase event.
i want to make a button with my ESP8266. It needs to communicate with my local Synapse (Matrix.org) Server.
I need to get my access_key, and a room_id and need to login my ESP8266.
So i have three http-methods. Each of it works fine, but when they are all three on my ESP8266 then it doesnt work. It seems that the first one dosent get a response but the second one. And then the skript stops because of some variable are nil. Thats why i didnt post the third-method.
My NodeMcu-Firmeware:
NodeMCU custom build by frightanic.com
branch: master
commit: 22e1adc4b06c931797539b986c85e229e5942a5f
SSL: true
modules: bit,cjson,crypto,encoder,file,gpio,http,net,node,sntp,tmr,uart,wifi,tls
build built on: 2017-05-01 14:03
powered by Lua 5.1.4 on SDK 2.0.0(656edbf)
My Code:
`ok, jsonheader = pcall(cjson.encode, {Accept="application/json"})
if ok then
print(jsonheader)
else
print("failed to encode!")
end
ok, jsonbody = pcall(cjson.encode, {type="m.login.password",user="admin", password="admin"})
if ok then
print(jsonbody)
else
print("failed to encode!")
end
http.post("http://localhost:8008/_matrix/client/r0/login", jsonheader, jsonbody , function(code, data)
if (code< 0) then
print("HTTP_GET request failed")
else
print(code, data)
accessToken = cjson.decode(data).access_token
print(accessToken)
end
end)
http.get("http://localhost:8008/_matrix/client/r0/directory/room/%23ButtonPrinter%3Ahomeserver", jsonheader, function(code1, data1)
if (code1< 0) then
print("HTTP_GET request failed")
else
print("___________________________________")
print(code1, data1)
roomId = cjson.decode(data1).room_id
print(roomId)
end
end)
The print out shows me, that it is not going in the first callback-method from http.post.
pin:6, level:1
Calling: 00000001
LED On
Push Counter is: 3
___________________________________
200 {"room_id":"!TpYsyBpFLoxXrbVBZv:homeserver","servers"["homeserver"]}
!TpYsyBpFLoxXrbVBZv:homeserver
And the log-file from the server shows that:
2017-05-06 10:09:16,233 - synapse.storage.TIME - 215 - INFO - - Total database time: 0.000% {update_cached_last_access_time(0): 0.000%, store_device(0): 0.000%, get_users_in_room(0): 0.000%} {}
2017-05-06 10:09:18,246 - synapse.access.http.8008 - 59 - INFO - GET-6- 192.168.178.XX - 8008 - Received request: GET /_matrix/client/r0/directory/room/%23ButtonPrinter%3Ahomeserver
2017-05-06 10:09:18,249 - synapse.util.async - 201 - INFO - GET-6- Acquired linearizer lock 'state_resolve_lock' for key frozenset([17, 18])
2017-05-06 10:09:18,250 - synapse.util.async - 208 - INFO - GET-6- Releasing linearizer lock 'state_resolve_lock' for key frozenset([17, 18])
2017-05-06 10:09:18,251 - synapse.access.http.8008 - 91 - INFO - GET-6- 192.168.178.XX - 8008 - {None} Processed request: 4ms (0ms, 0ms) (0ms/2) 69B 200 "GET /_matrix/client/r0/directory/room/%23ButtonPrinter%3Ahomeserver HTTP/1.1" "None"
2017-05-06 10:09:18,253 - synapse.access.http.8008 - 59 - INFO - POST-7- 192.168.178.XX - 8008 - Received request: POST /_matrix/client/r0/login
2017-05-06 10:09:18,545 - synapse.handlers.auth - 433 - INFO - POST-7- Logging in user #admin:homeserver on device DWOVBGCIOD
2017-05-06 10:09:18,548 - synapse.access.http.8008 - 91 - INFO - POST-7- 192.168.178.XX - 8008 - {None} Processed request: 295ms (0ms, 0ms) (3ms/5) 364B 200 "POST /_matrix/client/r0/login HTTP/1.1" "None"
2017-05-06 10:09:21,198 - synapse.handlers.typing - 79 - INFO - - Checking for typing timeouts
2017-05-06 10:09:21,199 - synapse.handlers.presence - 329 - INFO - - Handling presence timeouts
2017-05-06 10:09:26,197 - synapse.handlers.typing - 79 - INFO - - Checking for typing timeouts
2017-05-06 10:09:26,198 - synapse.handlers.presence - 329 - INFO - - Handling presence timeouts
2017-05-06 10:09:26,232 - synapse.storage.TIME - 215 - INFO - - Total database time: 0.042% {store_device(2): 0.017%, add_device_change_to_streams(1): 0.010%, add_access_token_to_user(1): 0.009%} {}
I tried so much, i wrapped all in tail-method, a tried it with an alarm.
But nothing works. I need all response in the right sequence.
What i am doing wrong?
I'm afraid that's sort of a classic.
It is not possible to execute concurrent HTTP requests using this module.
Source: https://nodemcu.readthedocs.io/en/latest/en/modules/http/
Since all http.xxx operations are asynchronous (all NodeMCU functions with callbacks are...) you're effectively trying to run http.post and http.get in parallel.
Solution 1: request chaining
http.post(url, jsonheader, jsonbody, function(code, data)
if (code < 0) then
print("HTTP request failed")
else
print(code, data)
-- http.get()
end
end)
Solution 2: task dispatching
http.post(url, jsonheader, jsonbody, function(code, data)
if (code < 0) then
print("HTTP request failed")
else
print(code, data)
node.task.post(function()
-- http.get()
end)
end
end)
See https://nodemcu.readthedocs.io/en/latest/en/modules/node/#nodetaskpost for details.
I'm working on grails 2.4.5.
I connect my project to oracle 11g.
In datasource, I add:
dataSource {
pooled = true
dialect = org.hibernate.dialect.Oracle10gDialect
driverClassName = 'oracle.jdbc.OracleDriver'
username = 'grails' // YOUR USERNAME AND PASS
password = 'grails'
url = 'jdbc:oracle:thin:localhost:1521:orcl'
dbCreate = 'update'
}
Then it connects and when I create new domain, new table in db creates.
However when I add new:
new Book(name:'The Strain').save(flush:true)
Then errors appear:
2015-07-29 17:10:30,036 [Thread-10] ERROR plugins.AbstractGrailsPluginManager - Plugin [controllers:2.4.5] could not reload changes to file [C:\Users\Thuc Tran\IdeaProjects\EmailTutorial\grails-app\controllers\emailtutorial\PlaceController.groovy]: Cannot invoke method getPropertyValue() on null object
Message: Cannot invoke method getPropertyValue() on null object
Line | Method
->> 120 | configureScaffoldingController in ScaffoldingGrailsPlugin
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ 105 | doCall in ScaffoldingGrailsPlugin$_closure3
Any solutions will be appreciated. Thanks.
I solved this problem. I post the solution for those who need it.
On oracle, create sequence, eg: BOOK_SEQ on my case. Make sure that on oracle, when you add new record, id will be auto increment.
Then on the domain class, static mapping quote, add:
static mapping = {
id generator:'sequence', params:[sequence:'BOOKS_SEQ']
}
So that's all.
If answer not clear, I feel free to answer.
Thanks.
I have created a service NotifierService to send emails using grails mail plugin.
class NotifierService {
MailService mailService
def sendWarningEmail(String name, String email, Date blockingDate) {
try {
mailService.sendMail {
to email
from "noreply-myApp#domain.com"
subject "Status message: Warning"
body (view:"/email/warningEmail", model:[
name:name,
blockingDate:blockingDate
])
}
} catch (Exception e) {
e.printStackTrace()
}
}
}
I have created another service ApplicationUtilService in which I am trying to use the NotifierService.
class ApplicationUtilService{
def notifierService
def notifyUser(){
notifierService.sendWarningEmail("User name", "user#domain.com", new Date())
}
}
I am trying to call notifyUser() in a grails job UpdateJob
class UpdateJob{
def applicationUtilService
static triggers = {
// Scehduling parameters
}
def execute(){
applicationUtilityService.notifyUser()
}
}
I get the following error
Error 2014-12-05 12:04:53,550 [quartzScheduler_Worker-1] ERROR listeners.ExceptionPrinterJobListener - Exception occurred in job: Grails Job
Message: java.lang.NullPointerException: Cannot invoke method notifyUser() on null object
Line | Method
->> 111 | execute in grails.plugins.quartz.GrailsJobFactory$GrailsJob
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 202 | run in org.quartz.core.JobRunShell
^ 573 | run . . in org.quartz.simpl.SimpleThreadPool$WorkerThread ...`
It works when I instantiate as
ApplicationUtilService applicationUtilService = new ApplicationUtilService()
instead of using grails dependency injection. Again, the same problem with the notifierService in ApplicationUtilService and fixed by instantiating same as above.
Now, the real problem is with the mailService. The instantiation as above didn't work. How could I resolve it
The Null Pointer is occurring on UpdateJob.applicationUtilService, so it seems like applicationUtilService isn't being injected into UpdateJob correctly. Is UpdateJob in the right package?
I have a simple Grails application. I did not author the front end, only the business logic layer.
I checked out all the source from SVN and the app starts, but I cannot load the main url. It errors out with the messages below. I have tried refreshing dependencies, but to no avail.
I have spelunked every file I could think of to try to fix this. What gets my attention is the FORWARD slash in front of the css, while the other delimiters in the path are backslashes.
Does anyone have any idea where this is going wrong and how to fix it? Maybe the front end developer needs to check something in?
Error 2013-07-31 13:50:24,036 [http-bio-8080-exec-4] ERROR [/MyClientAppName].[grails-errorhandler] - Servlet.service() for servlet grails-errorhandler threw exception
Message: Error applying layout : main
Line | Method
->> 1110 | runWorker in \grails-app\views\layouts\main.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 603 | run in ''
^ 722 | run . . . in ''
Caused by GroovyPagesException: Error processing GroovyPageView: Error executing tag <r:layoutResources>: Module [bootstrap] depends on resource [/css\bootstrap\bootstrap-responsive.css] but the file cannot be found
->> 464 | runWorker in \grails-app\views\layouts\main.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Caused by GrailsTagException: Error executing tag <r:layoutResources>: Module [bootstrap] depends on resource [/css\bootstrap\bootstrap-responsive.css] but the file cannot be found
->> 8 | doCall in C:/workspaces/GGTS1/MyClientAppName/grails-app/views/layouts/main.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Caused by IllegalArgumentException: Module [bootstrap] depends on resource [/css\bootstrap\bootstrap-responsive.css] but the file cannot be found
->