authenticator.pp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. { Demo Google-authenticator compatible authenticator app
  2. Copyright (C) 2022 Michael Van Canneyt [email protected]
  3. This source is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
  4. published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
  5. This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  6. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  7. A copy of the GNU General Public License is available on the World Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can
  8. also obtain it by writing to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.
  9. }
  10. {$mode objfpc}
  11. {$h+}
  12. uses sysutils, classes, onetimepass, inifiles, custapp;
  13. Type
  14. TMode = (mError,mHelp,mAdd,mDelete,mPrint,mGenerate,mList,mCheck);
  15. { TAuthenticatorApplication }
  16. TAuthenticatorApplication = Class(TCustomApplication)
  17. Private
  18. FIni : TMemIniFile;
  19. procedure CheckKey(aName, aCode: String);
  20. function getMode: TMode;
  21. procedure ListKeys;
  22. procedure PrintKey(aKey: String);
  23. procedure Usage(const aError: String);
  24. Public
  25. Constructor Create(aOwner : TComponent); override;
  26. Destructor Destroy; override;
  27. Procedure DoRun; override;
  28. end;
  29. Const
  30. SKeys = 'Keys';
  31. Need : array[TMode] of Integer = (0,0,2,1,1,0,0,2);
  32. constructor TAuthenticatorApplication.Create(aOwner: TComponent);
  33. begin
  34. inherited Create(aOwner);
  35. FIni:=TMemIniFile.Create(GetAppConfigFile(False));
  36. end;
  37. destructor TAuthenticatorApplication.Destroy;
  38. begin
  39. FreeAndNil(FIni);
  40. inherited Destroy;
  41. end;
  42. Procedure TAuthenticatorApplication.Usage(const aError : String);
  43. begin
  44. if (aError<>'') then
  45. Writeln('Error: ',aError);
  46. Writeln('Usage: ',ExtractFileName(ParamStr(0)),' [-a|-d|-h|-p|-g|-c|-l] [name [key|Value]');
  47. Writeln('If no options are specified, print key code');
  48. Writeln('-h --help This help text');
  49. Writeln('-a --add Add key with given name and key value');
  50. Writeln('-d --remove Remove key with given name');
  51. Writeln('-g --generate Generate and print new key');
  52. Writeln('-l --list List known keys');
  53. Writeln('-c --check Check code against key for given name');
  54. Writeln('config file: ',GetAppConfigFile(False));
  55. ExitCode:=Ord(AError<>'')
  56. end;
  57. Function TAuthenticatorApplication.getMode : TMode;
  58. var
  59. aMode : TMode;
  60. begin
  61. aMode:=mPrint;
  62. if HasOption('h','help') then
  63. aMode:=mHelp
  64. else if HasOption('a','add') then
  65. aMode:=mAdd
  66. else if HasOption('g','generate') then
  67. aMode:=mGenerate
  68. else if HasOption('c','check') then
  69. aMode:=mCheck
  70. else if HasOption('r','remove') then
  71. aMode:=mDelete
  72. else if HasOption('l','list') then
  73. aMode:=mList;
  74. result:=aMode;
  75. end;
  76. Procedure TAuthenticatorApplication.CheckKey(aName,aCode : String);
  77. Var
  78. S : String;
  79. aCount : Integer;
  80. begin
  81. S:=FIni.ReadString(SKeys,aName,'');
  82. if S='' then
  83. begin
  84. Writeln('No such key : ',aName);
  85. ExitCode:=1;
  86. end
  87. else
  88. begin
  89. if TOTPValidate(S,StrToIntDef(aCode,-1),1,aCount) then
  90. Writeln('Code OK')
  91. else
  92. begin
  93. Writeln('Code wrong');
  94. ExitCode:=1;
  95. end;
  96. end;
  97. end;
  98. Procedure TAuthenticatorApplication.PrintKey(aKey : String);
  99. Var
  100. S : String;
  101. begin
  102. S:=FIni.ReadString(SKeys,aKey,'');
  103. if S='' then
  104. begin
  105. Writeln('No such key : ',S);
  106. ExitCode:=1;
  107. end
  108. else
  109. Writeln('Token: ',TOTPGenerateToken(S));
  110. end;
  111. Procedure TAuthenticatorApplication.ListKeys;
  112. Var
  113. L : TStrings;
  114. I : Integer;
  115. N,K : String;
  116. begin
  117. L:=TStringList.Create;
  118. try
  119. Fini.ReadSectionValues(SKeys,L);
  120. Writeln('Known keys: ');
  121. For I:=0 to L.Count-1 do
  122. begin
  123. L.GetNameValue(I,N,K);
  124. Writeln(N,' : ',K);
  125. end;
  126. finally
  127. L.Free;
  128. end;
  129. end;
  130. Procedure TAuthenticatorApplication.DoRun;
  131. Const
  132. Opts : String ='harpgcl';
  133. LongOpts : Array of string = ('help','add','remove','print','generate','check','list');
  134. Var
  135. aErr : String;
  136. aMode : TMode;
  137. NonArgs : TStringArray;
  138. begin
  139. Terminate;
  140. aMode:=mError;
  141. aErr:=CheckOptions(Opts,LongOpts);
  142. NonArgs:=GetNonOptions(Opts,LongOpts);
  143. if (aErr='') then
  144. begin
  145. aMode:=GetMode;
  146. if aMode in [mAdd,mDelete,mGenerate] then
  147. if Length(NonArgs)<>Need[aMode] then
  148. begin
  149. aErr:=Format('Need %d arguments, got %d',[Need[aMode],Length(NonArgs)]);
  150. aMode:=mError;
  151. end;
  152. end;
  153. Case aMode of
  154. mError,mHelp:
  155. Usage(aErr);
  156. mAdd:
  157. begin
  158. FIni.WriteString(SKeys,NonArgs[0],NonArgs[1]);
  159. Fini.UpdateFile;
  160. end;
  161. mDelete:
  162. begin
  163. FIni.DeleteKey(SKeys,NonArgs[0]);
  164. Fini.UpdateFile;
  165. end;
  166. mPrint:
  167. begin
  168. if length(NonArgs)>0 then
  169. PrintKey(NonArgs[0])
  170. else
  171. Usage('');
  172. end;
  173. mGenerate:
  174. Writeln(TOTPSharedSecret());
  175. mCheck:
  176. begin
  177. CheckKey(NonArgs[0],NonArgs[1]);
  178. end;
  179. mList:
  180. ListKeys;
  181. end;
  182. end;
  183. begin
  184. CustomApplication:=TAuthenticatorApplication.Create(Nil);
  185. CustomApplication.Initialize;
  186. CustomApplication.Run;
  187. CustomApplication.Free;
  188. end.