You are not logged in.
Pages: 1
Hi anouri,
jsonobjects has per definition as far as i know no real order. So direct access via an index is a little bit risky, if the creator will change his output/implementation.
You can use the DocDict.GetEnumerator to loop through the object elements.
I can also have a look at the implementation of the interator. But direct access is not possible without "pointer magic" i think.
Hi ab,
any plans to support the proxy-protocol v2, that is often used by load balancers? Of course not so relevant for the http-stuff because of the x-forward-headers.
https://www.haproxy.org/download/1.8/do … otocol.txt
One future improvement (maybe) i would mention for your great framework:
One thing that was missing for me when using the your http-client with load-balancers:
To ensure that a client always uses the same server, the loadbancers uses "sticky-session-cookies". At the moment something like "allowcookies:= true" is missing in your http-client. I (mis-)used as workaround the indy (IdCookieManager) to set the cookie-header, after the first response for the next requests to automatic add the cookies back in the request.
What do you think? Is automatic cookie-handling something the http-client needs?
best regrards,
Tobias
What should i say - you are the best!
Thank you so much.
Hi ab,
thanks for the quick change.
it works for me. Is it possible to make WinInfoToParse usable (move to interface?)
{$ifdef OSWINDOWS}
procedure WinInfoToParse(const c: TWinCertInfo; out Info: TX509Parsed);
{$endif}
I also realized with my test that the the alternative DNS-Names are not yet parsed by WinCertCtxtDecode in (mormot.lib.sspi) as also mentioned in comment...
Info.SubjectAltNames := ''; // not yet part of TWinCertInfo
Any plans to integrate that Subject Alternative Name (SAN) attribute (OID: 2.5.29.17)?
https://learn.microsoft.com/en-us/windo … extensions
https://www.alvestrand.no/objectid/2.5.29.17.html
Thanks again.
Hi ab,
i must access some informations from the certificate from the peer for a connect client (THttpClientSocket).
Via the TNetTlsContext there is allready access to some Information (PeerIssuer,PeerSubject)
and if TNetTlsContext.WithPeerInfo = true also the full information (PeerInfo) in a text represantation.
Is it possible to append "CertInfo: TX509Parsed;" to the TNetTlsContext-Record and assign it to the NetTlsContext?
With the addition to the TNetTlsContext and a change in mormot.net.sock.windows.inc / TSChannelNetTls.AfterConnection line 2100
if Context.WithPeerInfo then
WinInfoToParse(nfo,Context.CertInfo);
the infos are accessible for the client. For this to work i must also put the definition of WinInfoToParse in the inferface part.
{$ifdef OSWINDOWS}
procedure WinInfoToParse(const c: TWinCertInfo; out Info: TX509Parsed);
{$endif}
not perfect and also only working for win/schannel at the moment.
Other option would be to fill the TX509Parsed via the PeerInfo-Text, but i didn't find a function in your great framework to interpret the text (opposite of ParsedToText). And maybe the PeerInfo text key-names are not a defacto-standard?
Maybe it is also possible to implement something that is already there for openssl (GetPeerCertFromUrl(const url: RawUtf8): PX509DynArray;) for the other clients (socket/schannel,...)
Be aware that there seems to be a breaktion change with the certificate-chain order in some windows-versions. Found this on curl implemention:
https://github.com/curl/curl/issues/9706
One use case would be:
Request the external wan-ip via a service (for example: https://ipv4.seeip.org). Make a connect with (IgnoreCert and WithPeerInfo) to find the webserver - hostname/common-name and maybe the alt.names from a service inside the lan, that don't know the public dns-names. After that the service can check if the "websites, https" is running via a second request. -> "Self Monitoring" https-endpoint from inside without the info from a config what url to monitor.
Thanks.
Best regards,
Tobias
OK, no problem, I don't want to use the certificate - it was just about decoding some information from it.
I have seen that there is also the function WinX509Parse(..), that was done the job and gives me the needed info in "PeerInfo"
Certificate:
Version: 3 (0x2)
Serial Number:
0a:fd:c7:7c:17:65:30:5f:57:84:c8:5d:94:38:29:a6
Signature Algorithm: sha384ECDSA
Issuer: CN=TSE CA 1, O=T-Systems International GmbH, OU=Telekom Security, C=DE
Validity
Not Before: Tue, 13 Sep 2022 12:54:20 GMT
Not After : Sun, 13 Aug 2028 23:59:59 GMT
Subject: dnQualifier=BSI-DSZ-CC-1121, C=DE, O=Swissbit AG, CN=3c96341676eeadf9b707253271a39eb35559b8c9034f2cbe9da7d2bfaab9b940
Subject Public Key Info:
Public Key Algorithm: ECC
ECC Public Key: (384 bit)
2f:af:24:a8:7e:66:b4:a1:c1:51:8c:fd:f1:a1:66:a4
0b:bd:a4:47:ba:8e:9b:e5:39:42:b7:1c:9f:6d:70:74
a2:5e:9b:19:e2:07:e5:56:60:d9:ee:c8:c2:3c:78:24
6f:5b:b8:d3:ba:b7:18:61:32:00:de:33:40:ee:3f:31
06:ab:ac:f3:6a:64:9f:0d:34:21:e2:23:c1:e6:56:dd
12:f0:0b:28:0f:0e:b6:7d:35:0b:07:fc:70:c3:25:fe
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
16:57:57:e6:5b:51:e9:86:cc:0e:7e:e3:5c:46:41:e3:f1:54:23:6e
X509v3 Authority Key Identifier:
82:b8:ab:33:09:a7:ff:f4:07:93:0f:24:34:fa:5e:75:f6:c9:04:3c
Hi ab,
i try to decode a X509-certificate from a pem. The certificate is from a TSE (Technische Sicherheits Einrichtung) that is needed for the german law to sign cashregister transactions.
The TX509Parse give me a "false". In "TXTbsCertificate.FromDer" and in "TX509.LoadFromDer" there is a big If-Check - sadly with out the reason for the "false".
After many steps in the debugger i see that the false comes from:
OidToXsa - '1.2.840.10045.4.3.3' is not in the ASN1_OID_SIGNATURE - definition. (OID 1.2.840.10045.4.3.3 ecdsa-with-SHA384) so is this a reason to give a false result?
sorry wrong ...
OID: '1.2.840.10045.2.1' OID2: '1.3.36.3.3.2.8.1.1.11' in OidToXka is not valid result = xkaNone - OID 1.3.36.3.3.2.8.1.1.11 seems to be "brainpoolP384r1" (https://learn.microsoft.com/en-us/windo … tic-curves)
FYI. this a hardware modul no software
If you whant do debug it youself here is the cert:
(string is without -----BEGIN CERTIFICATE-----#10 ... #10 -----END CERTIFICATE----- and linebreaks)
A Quick test via Online-Decode (https://www.sslshopper.com/certificate-decoder.html) gives me a valid result.
Certificate Information:
Common Name: 74024ea9846d8d438cb8c974af51602d0647403b723e7175f015fc0a38d601f0
Subject Alternative Names:
Organization: Swissbit AG
Organization Unit:
Locality:
State:
Country: DE
Valid From: September 13, 2022
Valid To: August 13, 2028
Issuer: TSE CA 1, T-Systems International GmbH
Serial Number: 2efc649c9776636526782db14e2646f9
Thank you again!
Hi,
sorry didn't see that you add a "SetBearer" for the IJsonClient, with this it is working.
nice weekend to all of you.
Hi ab,
you are the best!
It is working!
But one thing to mention/investigate: I think there is some problem with the assignment of the token via Variant (Pointer) - (Autofree?)
c.Http.Options.Auth.Token := api.GetRpcLogin('user@domain.tdl','SomePassword').token;
-> the Auth.Token in InternalSendRequest is empty.
if i set the token to a local rawutf8 and assign this to the c.Http.Options.Auth.Token it is filled and the next request is working.
s := api.GetRpcLogin('user@domain.tdl','SomePassword').token;
c.Http.Options.Auth.Token := s;
maybe critical/unexpected also on other assignments in the framework?
Hi ab,
thanks for the quick response.
You're right, I mixed up the internal "ApiVersion" with the openapi-spec.
In saggerui there is the hint "OAS 2.0" on top, so it isn't openapi spec v1
FYI: Because auf auth, the definition is defined as
"securityDefinitions": {
"JWT": {
"description": "Add the token prepending \"Bearer \" (without quotes) to it",
"in": "header",
"name": "Authorization",
"type": "apiKey"
}
},
"security": [
{
"JWT": []
}
],
Hi,
i give the generator a quick try againt a "PostgREST (https://postgrest.org/)" api. Generation works. But i must some changes in the client to support the the login on the api (AuthBearer)
The Login route looks like this in the automatic generated openapi (v1) from the PostgREST-Service:
"/rpc/login": {
"get": {
"parameters": [
{
"format": "text",
"in": "query",
"name": "email",
"required": true,
"type": "string"
},
{
"format": "text",
"in": "query",
"name": "pass",
"required": true,
"type": "string"
}
],
"produces": [
"application/json",
"application/vnd.pgrst.object+json;nulls=stripped",
"application/vnd.pgrst.object+json"
],
"responses": {
"200": {
"description": "OK"
}
},
"tags": [
"(rpc) login"
]
},
the via mopenapi.exe generated procedure for this route is:
procedure TAPIClient.GetRpcLogin(const Email: RawUtf8; const Pass: RawUtf8);
After i have change it to parse and return variant. It get the result token via json.
Is "produces": ["application/json"] not supported? - what is the right way to get the result from the ApiClient/IJsonClient?
But with the mod i got it working:
c := TJsonClient.Create('https://postgrest.domain.tld','');
api := TAPIClient.Create(c);
v := api.GetRpcLogin('user@domain.tdl','SomePassword');
d := DocDictFrom(v);
s := d.U['token'];
c.Http.Options.Auth.Scheme := wraBearer;
c.Http.Options.Auth.Token := s;
//next calls with token
artArr := api.GetArticle;
Also it would be nice to give the generator or created object (TAPIClient/TJsonClient) the some hints and params so that the login results in a prefilled auth infos after login.
It was just a quick test for me, so no not critical for me, just a hint and maybe feature improvement for you ab.
Maybe it is also a lack of none standard generation of openapi-spec from PostgREST.
Many thanks for your work on this module of the framework @Andreas and @ab
Hi Arnaud,
perfect. Thank you very much.
So i was in the right direction.
Tested and verified!
Tobias
Hi Arnaud,
yes i want a merge.
Looking for "merge" in mormot.core.variants points me to:
/// set a value, given its path
// - path is defined as a dotted name-space, e.g. 'doc.glossary.title'
// - aCreateIfNotExisting=true will force missing nested objects creation
// - aMergeExisting=true will merge aValue object with any existing object
// - returns nil if there is no item to be set at the supplied aPath
// - returns the address of the found or created value in aValue
// - you can set e.g. aPathDelim = '/' to search e.g. for 'parent/child'
function SetValueByPath(const aPath: RawUtf8; const aValue: variant;
aCreateIfNotExisting: boolean = false; aPathDelim: AnsiChar = '.';
aMergeExisting: boolean = false): PVariant;
because of "aMergeExisting=true will merge aValue object with any existing object"
is this an option? - I tried it, but I got an exception. Also i don't realize how to "Set" the root Path.
Thank you.
Hi,
I thought I could update the JSON object with an object that only contains part of the values. Unfortunately, the child objects are overwritten with the update object child element and the existing elements are lost.
Sample:
Json to update:
d1 := DocDict('
{
"name": "Mustermann",
"address": {
"city": "Musterstadt",
"street": "Lindenallee"
}
}');
Json Update input.
d2 := DocDict('{
"surname": "Max",
"address": {
"postal_code": "12345"
}
}');
d1.Update(d2);
Output:
{
"name": "Mustermann",
"address": {
"postal_code": "12345"
},
"surname": "Max"
}
Expected:
{
"name": "Mustermann",
"address": {
"city": "Musterstadt",
"street": "Lindenallee"
"postal_code": "12345"
},
"surname": "Max"
}
I have also tried "mDefault" as Model instead of mFastFloat.
Any chance to merge the json on all levels?
Thanks,
Tobias
Hi Chaa,
thank you for the clarification. I was already thinking something like that. Due to the code base that is used by Delphi 7 and Delphi 12, many things have not yet been converted to RawUTF8. So we must must be careful in various places. Some of the framework's operations also work with the D7:string without any problems.
I have detected an unexpected behavior on old Delphi compiler vs. newer one.
var s:string;
dynArr:TRawUtf8DynArray;
begin
s := 'test1';
setLength(dynArr,1);
dynArr[0]='test1';
Result := DynArray(TypeInfo(TRawUtf8DynArray),dynArr).IndexOf(s,true);
end;
-> Delphi7: Result=0, found
-> Delphi12: Result=-1, not found
If i cast the string to RawUtf8 or use RawUtf8 directly it is working.
var u:RawUtf8;
dynArr:TRawUtf8DynArray;
begin
u := 'test1';
setLength(dynArr,1);
dynArr[0]='test1';
Result := DynArray(TypeInfo(TRawUtf8DynArray),dynArr).IndexOf(u,true);
end;
-> Delphi7: Result=0, found
-> Delphi12: Result=0, found
I have done it now via an regex found on StackOverflow:
Regex: /[\/-]?((\w+)(?:[=:]("[^"]+"|[^\s"]+))?)(?:\s+|$)/g
With this regex i was able to build the RawUtf8DynArray and assign it on my own ExecutableCommandLine.RawParams before ExecutableCommandLine.Parse(CRLF,'/','-')
Hi,
is there any function to produce a valid array that can be assigned to cmdline.RawParams to support a CMD-Line like:
prog.exe /switch1 /param="param with spaces" /switch2
My try with:
CsvToRawUtf8DynArray(ownCmdLine,dynArray,' ');
procduces a invalid array because of the spaces in the doublequoted param.
Thanks.
Hi Arnaud,
today i tried agl.exe / mormot.app.agl.pas. It works perfectly for my use case. But i have a problem with a process that has a URI in the params.
For example "powershell" -command "$l = New-Object System.Net.HttpListener ; $l.Prefixes.Add('http://127.0.0.1:8080/'); $l.Start(); ..."
Problem detected in mormot.app.agl.Exec. "NormalizeFileName" is also done on the params. So "http://127.0.0.1:8080/" under Windows becomes "http:\\127.0.0.1:8080\". Under Unix, the same probably happens with backslashes in the parameters.
Thanks ab, for this great framwork!
Kind regards,
Tobias
Hi,
is it possible to serialize a record like this with definition RegisterFromText and without changing the record type (TTest) definition?
type TEnum = (eTagUnknown,eTagOne,eTagTwo)
TTest = record
id: cardinal;
test: string;
prices: array[1..3] of double;
tags[eTagOne..eTagTwo] of integer;
end;
const __TTest = 'id:cardinal;test:string;prices: array of double;tags: array of integer';
I have tried registriation with:
Rtti.RegisterTypes([TypeInfo(TEnum)]);
Rtti.RegisterFromText(TypeInfo(TTestRecord),__TTest);
but i get the error/exception on RegisterFromText:
Rtti.RegisterFromText(TTestRecord): text definition covers 16 bytes, but RTTI defined 40
Hi,
if i want to update the pivot-table with new entries i call "PivotTable.ManyAdd" with NoDuplicates=true. But the result is false if the record allready exists.
So the is no difference between ignore insert and a false result because of the false result from Client.Add or UseBatch.Add.
Maybe set the result to true if InternalIDFromSourceDest<>0 is better?
if NoDuplicates and
(InternalIDFromSourceDest(aClient, aSourceID, aDestID) <> 0) then
begin
result := true;
exit; // this TRecordReference pair already exists
end;
best regards,
Tobias
Hi,
are there any plans to support authentification for reqests and proxy-authentication via WinHttpSetCredentials like descriped at:
https://learn.microsoft.com/en-us/windo … in-winhttp
Best regards
Tobias
Pages: 1