#1 Re: mORMot 1 » JWT and interfaced based services with session » 2019-08-16 07:55:23

Hi @moctes

i have made the correction.
You can download the sample project here
https://1drv.ms/u/s!Ajd1--MjHzRWqxG2SeS … N?e=1JwpMd

PS : I don't have XE to validate the compilation.

#2 Re: mORMot 1 » JWT and interfaced based services with session » 2019-08-14 10:48:43

You can find a sample server here :
https://1drv.ms/u/s!Ajd1--MjHzRWqxG2SeS … N?e=1JwpMd


I'm using an overloaded version of TSQLRestDBServer to add two APIs:
- IsValidToken () to test whether the token is still active and allowed.
- RefreshToken () to regenerate it if it has expired. If the session is no longer existing, this method adds a new session.
  RefreshToken expects two parameters (User and password). 

These methods must be called with a bearer in the http header.

Compiled with Delphi XE3.

#3 Re: mORMot 1 » JWT and interfaced based services with session » 2019-08-13 16:40:32

Hi,

For those who are interested here is the latest version of this piece of code.
https://1drv.ms/u/s!Ajd1--MjHzRWqw7-27x … i?e=Oz6DWO


I will try to make a sample project quickly.
AB, if you can watch and tell me if I have not done a lot of bullshit, that would help me a lot.
Thank you.

#5 Re: mORMot 1 » JWT and interfaced based services with session » 2019-08-09 13:45:48

Hi,

I have made modifications for use TSQLHttpClient with this authentication.

Here the complete Unit :

unit Web.Serveur.U_JWT;

interface
uses
  Windows,
  SysUtils,
  Classes,
  SynZip,
  SynLZ,
  SynCrtSock,
  {$ifndef NOHTTPCLIENTWEBSOCKETS}
  SynBidirSock, // for WebSockets
  {$endif}
  SynCrypto,    // for hcSynShaAes
  SynCommons,
  SynLog,
  mORMot,
  mORMotHttpClient;

type
  TSQLRestRoutingREST_JWT = class(TSQLRestRoutingREST)
  protected
    procedure AuthenticationFailed(Reason: TNotifyAuthenticationFailedReason); override;
  end;

  TSQLRestServerAuthenticationJWT = class(TSQLRestServerAuthenticationHttpBasic)
  protected
    function CheckPassword(Ctxt: TSQLRestServerURIContext;
      User: TSQLAuthUser; const aPassWord: RawUTF8): boolean; override;

    procedure SessionCreate(Ctxt: TSQLRestServerURIContext; var User: TSQLAuthUser); override;
    function getAlgo(const Value : RawUTF8) : TSignAlgo;
    procedure AuthenticationFailed(Ctxt: TSQLRestServerURIContext; Reason: TNotifyAuthenticationFailedReason);

    class function ClientGetSessionKey(Sender: TSQLRestClientURI;
      User: TSQLAuthUser; const aNameValueParameters: array of const): RawUTF8; override;
  public
    function RetrieveSession(Ctxt: TSQLRestServerURIContext): TAuthSession; override;
    function Auth(Ctxt: TSQLRestServerURIContext): boolean; override;

    class function ClientSetUser(Sender: TSQLRestClientURI; const aUserName, aPassword: RawUTF8;
      aPasswordKind: TSQLRestServerAuthenticationClientSetUserPassword=passClear;
      const aHashSalt: RawUTF8=''; aHashRound: integer=20000): boolean; override;
  end;

  TSQLHttpClientJWT = class(TSQLHttpClientRequest)
  private
    fJWT: RawUTF8;
  protected
    procedure InternalSetClass; override;
    function InternalRequest(const url, method: RawUTF8;
      var Header, Data, DataType: RawUTF8): Int64Rec; override;
  public
    function SetUser(const aUserName, aPassword: RawUTF8;
      aHashedPassword: Boolean=false): boolean; reintroduce;
    property jwt : RawUTF8 read fJWT write fJWT;
  end;

implementation

function HeaderOnce(const Head : RawUTF8; upper: PAnsiChar): RawUTF8;
  {$ifdef HASINLINE}inline;{$endif}
begin
  if (Head <> '') then
    result := FindIniNameValue(pointer(Head),upper)
  else result := '';
end;

{ TSQLRestRoutingREST_JWT }

procedure TSQLRestRoutingREST_JWT.AuthenticationFailed(
  Reason: TNotifyAuthenticationFailedReason);
begin
  inherited AuthenticationFailed(Reason);
end;

{ TSQLRestServerAuthenticationJWT }

function TSQLRestServerAuthenticationJWT.Auth(
  Ctxt: TSQLRestServerURIContext): boolean;
var aUserName, aPassWord : RawUTF8;
    User: TSQLAuthUser;
begin
  result := False;
  if AuthSessionRelease(Ctxt) then
    exit;

  if not Assigned(fServer.JWTForUnauthenticatedRequest) then begin
      AuthenticationFailed(Ctxt, afJWTRequired);
    Exit;
  end;

  aUserName := Ctxt.InputUTF8OrVoid['UserName'];
  aPassWord := Ctxt.InputUTF8OrVoid['Password'];

  if (aUserName<>'') and (length(aPassWord)>0) then begin
    User := GetUser(Ctxt,aUserName);
    try
      result := User<>nil;
      if result then begin
        if CheckPassword(Ctxt, User, aPassWord) then
          SessionCreate(Ctxt, User)
        else AuthenticationFailed(Ctxt, afInvalidPassword);
      end
      else AuthenticationFailed(Ctxt, afUnknownUser);
    finally
      if result then User.Free;
    end;
  end
  else AuthenticationFailed(Ctxt, afUnknownUser);
end;

procedure TSQLRestServerAuthenticationJWT.AuthenticationFailed(Ctxt: TSQLRestServerURIContext;
  Reason: TNotifyAuthenticationFailedReason);
begin
  if Ctxt is TSQLRestRoutingREST_JWT then
    TSQLRestRoutingREST_JWT(Ctxt).AuthenticationFailed(Reason);
end;

function TSQLRestServerAuthenticationJWT.CheckPassword(
  Ctxt: TSQLRestServerURIContext; User: TSQLAuthUser;
  const aPassWord: RawUTF8): boolean;
var expectedPass: RawUTF8;
begin
  expectedPass := User.PasswordHashHexa;
  User.PasswordPlain := aPassWord;
  User.PasswordHashHexa := SHA256(aPassWord);
  result := IdemPropNameU(User.PasswordHashHexa,expectedPass);
end;

class function TSQLRestServerAuthenticationJWT.ClientGetSessionKey(
  Sender: TSQLRestClientURI; User: TSQLAuthUser;
  const aNameValueParameters: array of const): RawUTF8;
var resp: RawUTF8;
    values: array[0..9] of TValuePUTF8Char;
    a: integer;
    algo: TSQLRestServerAuthenticationSignedURIAlgo absolute a;
begin
  Result := '';
  if (Sender.CallBackGet('Auth',aNameValueParameters,resp)=HTTP_SUCCESS) then
    result := resp;
end;

class function TSQLRestServerAuthenticationJWT.ClientSetUser(
  Sender: TSQLRestClientURI; const aUserName, aPassword: RawUTF8;
  aPasswordKind: TSQLRestServerAuthenticationClientSetUserPassword;
  const aHashSalt: RawUTF8; aHashRound: integer): boolean;
var res: RawUTF8;
    U: TSQLAuthUser;
    vTmp : Variant;
begin
  result := false;
  if (aUserName='') or (Sender=nil) then
    exit;
  if not Sender.InheritsFrom(TSQLHttpClientJWT) then
    exit;

  if aPasswordKind<>passClear then
    raise ESecurityException.CreateUTF8('%.ClientSetUser(%) expects passClear',
      [self,Sender]);
  Sender.SessionClose; // ensure Sender.SessionUser=nil
  try // inherited ClientSetUser() won't fit with Auth() method below
    ClientSetUserHttpOnly(Sender,aUserName,aPassword);
    TSQLHttpClientJWT(Sender).jwt := '';
    U := TSQLAuthUser(Sender.Model.GetTableInherited(TSQLAuthUser).Create);
    try
      U.LogonName := trim(aUserName);
      res := ClientGetSessionKey(Sender,U,['Username', aUserName, 'password', aPassword]);

      if res<>'' then begin
        vTmp := _JsonFast(res);
        if DocVariantType.IsOfType(vTmp) then begin
          result := TSQLHttpClientJWT(Sender).SessionCreate(self,U,TDocvariantData(vTmp).U['result']);
          if result then
            TSQLHttpClientJWT(Sender).jwt := TDocvariantData(vTmp).U['jwt'];
        end;
      end;
    finally
      U.Free;
    end;
  finally
    if not result then begin
      // on error, reverse all values
      TSQLHttpClientJWT(Sender).jwt := '';
    end;
    if Assigned(Sender.OnSetUser) then
      Sender.OnSetUser(Sender); // always notify of user change, even if failed
  end;
end;

function TSQLRestServerAuthenticationJWT.getAlgo(
  const Value: RawUTF8): TSignAlgo;
var i : TSignAlgo;
begin
  Result := saSha256;
  for i := low(JWT_TEXT) to High(JWT_TEXT) do
    if SameTextU(Value, JWT_TEXT[i]) then begin
      result := i;
      break;
    end;
end;

function TSQLRestServerAuthenticationJWT.RetrieveSession(
  Ctxt: TSQLRestServerURIContext): TAuthSession;
var aUserName : RawUTF8;
    User: TSQLAuthUser;
    i : Integer;
    tmpIdsession : Cardinal;
    vSession : variant;
    pSession : PDocVariantData;
    vSessionPrivateSalt : RawUTF8;
begin
  result := inherited RetrieveSession(Ctxt);

  if result <> nil then
    Exit;

  if not Assigned(fServer.JWTForUnauthenticatedRequest) then
    Exit;

  vSessionPrivateSalt := '';
  if Ctxt.AuthenticationBearerToken <> '' then
    if Ctxt.AuthenticationCheck(fServer.JWTForUnauthenticatedRequest) then begin
      aUserName := Ctxt.JWTContent.reg[jrcIssuer];
      User := GetUser(Ctxt,aUserName);
      try
        if User <> nil then begin
          if Ctxt.Server.Sessions <> nil then begin
            if Ctxt.JWTContent.data.GetValueIndex('sessionkey') >= 0 then begin
              vSession := _Json(Ctxt.JWTContent.data.U['sessionkey']);
              if DocVariantType.IsOfType(vSession) then
                vSessionPrivateSalt := vSession.Result;
            end;

            Ctxt.Server.Sessions.Safe.Lock;
            try
              // Search session for User
              if (reOneSessionPerUser in Ctxt.Call^.RestAccessRights^.AllowRemoteExecute) and
                (Ctxt.Server.Sessions<>nil) then
                for i := 0 to Pred(Ctxt.Server.Sessions.Count) do
                  if TAuthSession(Ctxt.Server.Sessions[i]).User.ID = User.ID then begin
                    Result := TAuthSession(Ctxt.Server.Sessions[i]);
                    Ctxt.Session := Result.IDCardinal;
                    break;
                  end;

              // Search session by privatesalt
              if result = nil then
                for i := 0 to Pred(Ctxt.Server.Sessions.Count) do
                  if SameTextU(vSessionPrivateSalt, TAuthSession(Ctxt.Server.Sessions[i]).ID + '+' + TAuthSession(Ctxt.Server.Sessions[i]).PrivateKey) then begin
                    Result := TAuthSession(Ctxt.Server.Sessions[i]);
                    Ctxt.Session := Result.IDCardinal;
                    break;
                  end;

            finally
              Ctxt.Server.Sessions.Safe.unLock;
            end;
          end;
        end;
      finally
        User.free;
      end;
    end;
end;

procedure TSQLRestServerAuthenticationJWT.SessionCreate(
  Ctxt: TSQLRestServerURIContext; var User: TSQLAuthUser);
var Session: TAuthSession;
    i : Integer;
    Token : RawUTF8;
    jWtClass : TJWTSynSignerAbstractClass;
    vPass, vUser, Signat, vSessionKey : RawUTF8;
    vTmp : Variant;
begin
  vUser := User.LogonName;
  vPass := User.PasswordHashHexa;
  inherited SessionCreate(Ctxt, User);
  if Ctxt.Call^.OutStatus = HTTP_SUCCESS then begin
    if fServer.JWTForUnauthenticatedRequest <> nil then begin
      jwtClass := JWT_CLASS[getAlgo(fServer.JWTForUnauthenticatedRequest.Algorithm)];
      Token := (fServer.JWTForUnauthenticatedRequest as jwtClass).Compute([
                                                                           'sessionkey', Ctxt.Call^.OutBody],
                                                                           vUser,
                                                                           'jwt.access',
                                                                           '',0,60, @Signat);
      vTmp := _JsonFast(Ctxt.Call^.OutBody);
      if DocVariantType.IsOfType(vTmp) then
        Ctxt.Call^.OutBody := _Obj(['result', TDocvariantData(vTmp).U['result'], 'jwt', Token]);
    end;
  end;
end;

{ TSQLHttpClientJWT }

function TSQLHttpClientJWT.InternalRequest(const url, method: RawUTF8;
  var Header, Data, DataType: RawUTF8): Int64Rec;
var vBasic : RawUTF8;
    h : Integer;
begin
  if fjwt <> '' then begin // Change Header if jwt exist
    vBasic := HeaderOnce(Header, 'AUTHORIZATION: BASIC ');
    if vBasic <> '' then begin
      h := PosEx(vBasic, Header);
      if h = 22 then
        header := copy(Header, h + Length(vBasic), Length(header))
      else header := copy(Header, 1, h - 21) + copy(Header, h + Length(vBasic), Length(header));
      header := Trim(header);
    end;
    Header := trim(HEADER_BEARER_UPPER + fJWT + #13#10 + Header);
  end;
  result := inherited InternalRequest(url, method, Header, Data, DataType);
end;

procedure TSQLHttpClientJWT.InternalSetClass;
begin
  fRequestClass := TWinHTTP;
  inherited;
end;

function TSQLHttpClientJWT.SetUser(const aUserName, aPassword: RawUTF8;
  aHashedPassword: Boolean): boolean;
const HASH: array[boolean] of TSQLRestServerAuthenticationClientSetUserPassword =
  (passClear, passHashed);
begin
  if self=nil then begin
    result := false;
    exit;
  end;
  result := TSQLRestServerAuthenticationJWT.
    ClientSetUser(self,aUserName,aPassword,HASH[aHashedPassword]);
end;

end.

TSQLRestServerAuthenticationJWT.Auth() method return a RawUTF8 JSON Object containing two fields :
- result : session privatesalt (ID + '+' + privatekey)
- jwt :  the Token

The TSQLHttpClientJWT class is to used with Delphi client.

FClient := TSQLHttpClientJWT.Create(SERVER_ADDRESS, DEFAULT_PORT, FDBModel);
if FClient.SetUser('synopse', 'mormot', False) then
....

For Ajax client, you must parse Auth() API response.

$("#submit").click(function(){
 
 var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(event) {
      if (this.readyState === XMLHttpRequest.DONE) {
        if (this.status === 200) {
            tmp = JSON.parse(xhr.responseText);
            sessionStorage.setItem("jwt",tmp.jwt);
        } else {
            tmp = xhr.statusText;
        }
      }	  
    };

    username = $("#login").val();
    mpass = $("#mdp").val();
	
    xhr.open('GET', "http://127.0.0.1/MyServer/Auth?username=" + username + "&password=" + mpass, true);
    xhr.send(null);    
});

And use jwt value in each call :

var GET_Testjwt = function(jwt,callback){
  var xhr = new XMLHttpRequest();
   xhr.onreadystatechange = function(event) {
      if (this.readyState === XMLHttpRequest.DONE) {
        if (this.status === 200) {
            response = xhr.responseText;
        } else {
            response = xhr.statusText;
        }
       callback(200, response);
      }	  
    };
  jwt = sessionStorage.getItem("jwt");
  xhr.open('GET', "http://127.0.0.1/MyServer/" + arequest, true);
  xhr.setRequestHeader('Authorization', ' bearer ' + jwt);
  xhr.send(null);    
}

I hope I did not forget anything.
The code runs on the tests and will soon be in production. I'll see if it's okay.
Any comments or suggestions are welcome.

#6 Re: mORMot 1 » Serialize array of records using TDynArray and error on deserialize » 2019-08-08 16:39:31

Hi,

did you try to initialize OtherDynarray ?
Like OtherDynarray.Init(TypeInfo(TArray<TFieldData>), Tab)

#7 Re: mORMot 1 » JWT and interfaced based services with session » 2019-08-08 12:02:42

Hi,

I have done this to keep session :

Implement a TSQLRestServerAuthenticationHttpBasic :

  TSQLRestServerAuthenticationJWT = class(TSQLRestServerAuthenticationHttpBasic)
  protected
    procedure SessionCreate(Ctxt: TSQLRestServerURIContext; var User: TSQLAuthUser); override;
    function getAlgo(const Value : RawUTF8) : TSignAlgo;
    procedure AuthenticationFailed(Ctxt: TSQLRestServerURIContext; Reason: TNotifyAuthenticationFailedReason);
  public
    function RetrieveSession(Ctxt: TSQLRestServerURIContext): TAuthSession; override;
    function Auth(Ctxt: TSQLRestServerURIContext): boolean; override;
  end;
....
procedure TSQLRestServerAuthenticationJWT.SessionCreate(
  Ctxt: TSQLRestServerURIContext; var User: TSQLAuthUser);
var Session: TAuthSession;
    i : Integer;
    Token : RawUTF8;
    jWtClass : TJWTSynSignerAbstractClass;
    vUser, Signat : RawUTF8;
begin
  vUser := User.LogonName;
  inherited SessionCreate(Ctxt, User);
  if Ctxt.Call^.OutStatus = HTTP_SUCCESS then begin
    if fServer.JWTForUnauthenticatedRequest <> nil then begin
      jwtClass := JWT_CLASS[getAlgo(fServer.JWTForUnauthenticatedRequest.Algorithm)];
      (fServer.JWTForUnauthenticatedRequest as jwtClass).SignPrepared.Init(saSha256, SHA256(Ctxt.UserAgent + 'salt'));
      Token := fServer.JWTForUnauthenticatedRequest.Compute(['sessionkey', Ctxt.Call^.OutBody],
                                                             vUser,
                                                             'MyPortail',
                                                             '',0,60, @Signat);
      Ctxt.Call^.OutBody := Token; // <- on retourne le token
    end;
  end;
end;

function TSQLRestServerAuthenticationJWT.getAlgo(
  const Value: RawUTF8): TSignAlgo;
var i : TSignAlgo;
begin
  Result := saSha256;
  for i := low(JWT_TEXT) to High(JWT_TEXT) do
    if SameTextU(Value, JWT_TEXT[i]) then begin
      result := i;
      break;
    end;
end;

procedure TSQLRestServerAuthenticationJWT.AuthenticationFailed(Ctxt: TSQLRestServerURIContext;
  Reason: TNotifyAuthenticationFailedReason);
begin
  if Ctxt is TSQLRestRoutingREST_JWT then
    TSQLRestRoutingREST_JWT(Ctxt).AuthenticationFailed(Reason);
end;

function TSQLRestServerAuthenticationJWT.RetrieveSession(
  Ctxt: TSQLRestServerURIContext): TAuthSession;
var aUserName : RawUTF8;
    User: TSQLAuthUser;
    i : Integer;
    tmpIdsession : Cardinal;
    vSession : variant;
    pSession : PDocVariantData;
    vSessionPrivateSalt : RawUTF8;
begin
  result := inherited RetrieveSession(Ctxt);

  if result <> nil then
    Exit;

  if not Assigned(fServer.JWTForUnauthenticatedRequest) then
    Exit;

  vSessionPrivateSalt := '';
  if Ctxt.AuthenticationBearerToken <> '' then
    if Ctxt.AuthenticationCheck(fServer.JWTForUnauthenticatedRequest) then begin
      aUserName := Ctxt.JWTContent.reg[jrcIssuer];
      User := GetUser(Ctxt,aUserName);
      try
        if User <> nil then begin
          if Ctxt.Server.Sessions <> nil then begin
            if Ctxt.JWTContent.data.GetValueIndex('sessionkey') >= 0 then begin
              vSession := _Json(Ctxt.JWTContent.data.U['sessionkey']);
              if DocVariantType.IsOfType(vSession) then
                vSessionPrivateSalt := vSession.Result;
            end;

            Ctxt.Server.Sessions.Safe.Lock;
            try
              // Search session by privatesalt
              for i := 0 to Pred(Ctxt.Server.Sessions.Count) do
                if SameTextU(vSessionPrivateSalt, TAuthSession(Ctxt.Server.Sessions[i]).ID + '+' + TAuthSession(Ctxt.Server.Sessions[i]).PrivateKey) then begin
                  Result := TAuthSession(Ctxt.Server.Sessions[i]);
                  Ctxt.Session := Result.IDCardinal;
                  break;
                end;

              // Search session for User
              if result = nil then
                for i := 0 to Pred(Ctxt.Server.Sessions.Count) do
                  if TAuthSession(Ctxt.Server.Sessions[i]).User.ID = User.ID then begin
                    Result := TAuthSession(Ctxt.Server.Sessions[i]);
                    Ctxt.Session := Result.IDCardinal;
                    break;
                  end;

            finally
              Ctxt.Server.Sessions.Safe.unLock;
            end;
          end;
        end;
      finally
        User.free;
      end;
    end;
end;

function TSQLRestServerAuthenticationJWT.Auth(
  Ctxt: TSQLRestServerURIContext): boolean;
var aUserName, aPassWord : RawUTF8;
    User: TSQLAuthUser;
begin
  result := False;
  if AuthSessionRelease(Ctxt) then
    exit;

  if not Assigned(fServer.JWTForUnauthenticatedRequest) then begin
      AuthenticationFailed(Ctxt, afJWTRequired);
    Exit;
  end;

  aUserName := Ctxt.InputUTF8OrVoid['UserName'];
  aPassWord := Ctxt.InputUTF8OrVoid['Password'];

  if (aUserName<>'') and (length(aPassWord)>0) then begin
    User := GetUser(Ctxt,aUserName);
    try
      result := User<>nil;
      if result then begin
        if CheckPassword(Ctxt, User, aPassWord) then
          SessionCreate(Ctxt, User)
        else AuthenticationFailed(Ctxt, afInvalidPassword);
      end
      else AuthenticationFailed(Ctxt, afUnknownUser);
    finally
      if result then User.Free;
    end;
  end
  else AuthenticationFailed(Ctxt, afUnknownUser);
end;

Implement the TSQLRestRoutingREST for access to protected AuthenticationFailed function :

  TSQLRestRoutingREST_JWT = class(TSQLRestRoutingREST)
  protected
    procedure AuthenticationFailed(Reason: TNotifyAuthenticationFailedReason); override;
  end;
....
procedure TSQLRestRoutingREST_JWT.AuthenticationFailed(
  Reason: TNotifyAuthenticationFailedReason);
begin
  inherited AuthenticationFailed(Reason);
end;

For the Rest server creation :

   fRestServer.AuthenticationRegister(TSQLRestServerAuthenticationJWT);
   fRestServer.ServicesRouting := TSQLRestRoutingREST_JWT;
   fRestServer.JWTForUnauthenticatedRequest := fServerSettings.AuthenticationMode.JWTClass.Create('secret', 0, [jrcIssuer, jrcSubject], [], 60);

JWTForUnauthenticatedRequest instance is used in TSQLRestServerAuthenticationJWT.

#9 mORMot 1 » MormotHTTPServer and NOSSPIAUTH » 2019-03-05 10:35:28

Chris75018
Replies: 2

hi,

when I define NOSSPIAUTH directive, I have a compilation error under TSQLHTTPServer.Create().
I make this modification :

const AUTH: array[TSQLHttpServerRestAuthentication] of TSQLRestServerAuthenticationClass = (
  // adDefault, adHttpBasic, adWeak, adSSPI
  TSQLRestServerAuthenticationDefault, TSQLRestServerAuthenticationHttpBasic,
  TSQLRestServerAuthenticationNone,
  {$ifdef MSWINDOWS}
    /*...Modif....*/
     {$ifdef SPPIAUTH}TSQLRestServerAuthenticationSSPI{$else}nil{$endif}
   /*...End...*/
  {$else}nil{$endif});

best regards

Christophe

#10 Re: mORMot 1 » Fix to timestamp bug regression » 2017-05-19 14:05:26

That don't works for me too.
The @ab solution works.

--> ftDateTime: PDateTimeRec(Dest)^.DateTime := TimeStampToMSecs(TS);

If TS have not Time part (TS.Time = 0) then PDateTime(Data)^ doesn't have a valid date.

I used DataSetToJSON(MyInterbaseQuery) to store data in RawUTF8 buffer.
I reload data with TSynSQLTableDataSet.CreateFromJSON(nil, MyBuffer, MyTSQLFieldsType)

#11 mORMot 1 » Unknown identifier : TSynExtended » 2015-05-04 15:47:37

Chris75018
Replies: 1

Hi,

when i compiled a package including Mormot unit under Delphi XE3, i've got this compilator error :
[dcc32 Error] mORMot.pas(2363):E2003 Unknown identifier : "TsynExtended"

Is everybody have an idea ?

PS : USEPACKAGES is activate in Synopse.inc

#12 Re: mORMot 1 » TRawByteStringArray » 2015-04-17 07:48:38

Next time, I will try to sign my neurons. smile

Thank's a lot

#13 mORMot 1 » TRawByteStringArray » 2015-04-16 10:58:30

Chris75018
Replies: 2

Hi,

I'm trying to use a TRawByteStringArray Field in a TSQLRecord Object.
Under Delphi XE3 (64 bit platform for compilation) compilater report this exception :
E2100 : Data type too large: exceeds 2 GB

The only way I have found is to change TRawByteStringArray declaration from static array to dynamic array in Syncommons.

//  TRawByteStringArray = array[0..MaxInt div SizeOf(RawByteString)-1] of RawByteString;
  TRawByteStringArray = array of RawByteString;

What's your opinion about this modification ?

thank's in advance.

#14 Re: mORMot 1 » Cannot find how to Read TbyteDynArray from TSQLTableJSON » 2015-03-04 11:10:47

Hi

when i use TByteDynArray(Table.GetBytes(...)) the result contains more bytes (7) than the stored array (perhaps Base64Encode ?).

With TByteDynArray(Table.GetBytes(...))  --> (1,0,12,15,18,48,54,1,2,3,4,5,6,7,8,9,10,11,12)
With client.Retrieve(row, MySQLrecord) --> (1,2,3,4,5,6,7,8,9,10,11,12)

But if i use MySQLRecord.FillFrom(Table) all is fine.
It's good for me.

#16 Re: mORMot 1 » Cannot find how to Read TbyteDynArray from TSQLTableJSON » 2015-03-03 19:49:53

I've done it first with table.GetBytes but I have don't find how to load the TByteDynArray variable with it.
Do you have a sample. I dont find anything in the documentation and in the forum.

Thanks.

#17 mORMot 1 » Cannot find how to Read TbyteDynArray from TSQLTableJSON » 2015-03-03 18:03:10

Chris75018
Replies: 5

Hi,

I didin't find how to read TByteDynArray Field from a TSQLHttpClientWinHTTP.list() result.

  TRHhisto = class(TSQLRecord)
  private
    fHisBuffer    : TRawUTF8DynArray;
    fHisMois      : TByteDynArray;
  public
    procedure Clear; override;
  published
    property hisBuffer   : TRawUTF8DynArray   read fHisBuffer   write fHisBuffer;
    property hisMois     : TByteDynArray      read fHisMois     write fHisMois;
  end;
{...}
var Table : TSQLTableJSON;
      bl : TSQLRawBlob;
{...}
  Table := Client.List([TRHhisto], 'rowID, HISPERID, HISMOIS', StringToUTF8(sWhere));
  if Table <> nil then 
  begin
     {...}
     bl := Table.getBlob(idx, Table.fieldIndex('HISMOIS'));

     ------> How to convert bl to a TByteDynArray variable ?

  end;

Thanks in advance.

#19 mORMot 1 » PosEx result in PUREPASCAL » 2014-11-12 17:26:35

Chris75018
Replies: 3

HI,

when i execute MVCServer sample with PUREPASCAL Directive On, i have this error :

Unit Mormot.pas
constructor TSQLRecordProperties.Create(aTable: TSQLRecordClass);
{...}
line 34813 :     
  if PosEx(' '+LowerCase(F.Name)+' ',SQLITE3_KEYWORDS)>0 then // Result = 226 with F.Name = 'Title'
      raise EORMException.CreateUTF8('%.% field name conflicts with a SQL keyword',

If PUREPASCAL is Off, the result of PosEx is 0.

#20 Re: mORMot 1 » MongoDB : unknown collection "system.indexed" » 2014-05-14 13:37:49

Thanks for your reply and sorry, i have not restart server after installation of MongoDB.
After restart, it's work fine.

#21 Re: mORMot 1 » MongoDB : unknown collection "system.indexed" » 2014-05-13 07:38:37

Yes I do.
MongoDB version : 2.6.1 (x64-2008 msi)
Windows 8 x64 

I've got same results with Windows server 2008 x64, Windows server 2012 x64 and MongoDB 2.6.1 x32 on Windows XP sp 4.

#22 mORMot 1 » MongoDB : unknown collection "system.indexed" » 2014-05-12 08:42:17

Chris75018
Replies: 4

Hello there,

when i use this piece of code for initialized a new MongoDB database

  MongoClient := TMongoClient.Create(Host_ip,27017);
  DB := MongoClient.Database[DTB_name];
  Model := TSQLModel.Create([TMYMODEL]);
  Client := TSQLRestClientDB.Create(Model,nil,':memory:',TSQLRestServerDB);
  try
    if StaticMongoDBRegister(TMYMODEL,
                             Client.Server,
                             DB,
                             DTB_name)=nil then
      raise Exception.Create('Error');

i've got this error : Unknown collection "system.indexes"
only on a new installation of MongoDB server and when a field is marked "AS_UNIQUE" in TSQLMODEL declaration.

But when i used a direct mongoDB database access as in your post http://blog.synopse.info/post/2014/05/0 … ase-access , system.indexes collection is correctly initialized.
So,
- did i must initialized database first with direct access ?
- Is there something wrong in my code ?

Thank´s for your time

#23 Re: mORMot 1 » Change filename of a STATICFILE document from CALLBACKGET Method ? » 2012-09-17 08:14:20

Sorry,

All is in the header :

        sIn := StringToUTF8(vfilename);
        sHead := 'Content-Type: ' + HTTP_RESP_STATICFILE  + #13 +
                 'Content-Disposition: attachment; filename="MyInstallprog.exe"';
        aParams.Head^ := sHead;
        aParams.Resp := sIn;
        result := 200;

#24 mORMot 1 » Change filename of a STATICFILE document from CALLBACKGET Method ? » 2012-09-14 15:39:06

Chris75018
Replies: 2

Hi,
When I  try to download a file (HTTP_RESP_STATICFILE) from a CALLBACKGET Method (TSQLRESTServer class), the output filename is the CALLBACKGET Method name.
Is anyone know what must i do for change it ?

        sIn := StringToUTF8(vfilename);
        sHead := 'Content-Type: ' + HTTP_RESP_STATICFILE;
        aParams.Head^ := sHead;
        aParams.Resp := sIn;
        result := 200;

The aim is to download a client application for a local network server from his location (SERVERIP/client/Index?myInstallclient.exe).

Board footer

Powered by FluxBB