Compare commits
	
		
			183 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					85e24b430d | ||
| 
						 | 
					d5b54a67f4 | ||
| 
						 | 
					cb5dcde0ca | ||
| 
						 | 
					1977ecdfb7 | ||
| 
						 | 
					7be170a0bd | ||
| 
						 | 
					1d703e1737 | ||
| 
						 | 
					22ddb40d4c | ||
| 
						 | 
					791b72aec4 | ||
| 
						 | 
					46b9524903 | ||
| 
						 | 
					bb09f919e6 | ||
| 
						 | 
					8d04cbc059 | ||
| 
						 | 
					073856d385 | ||
| 
						 | 
					c782981ca7 | ||
| 
						 | 
					ca3691e665 | ||
| 
						 | 
					be2ffc86ec | ||
| 
						 | 
					75ebc0771c | ||
| 
						 | 
					d050635a99 | ||
| 
						 | 
					e3592b5fe6 | ||
| 
						 | 
					9eec54effb | ||
| 
						 | 
					6a7ae342dc | ||
| 
						 | 
					5b3205823e | ||
| 
						 | 
					db45a01bce | ||
| 
						 | 
					d2f70ec82d | ||
| 
						 | 
					2b01453970 | ||
| 
						 | 
					68ccc4da93 | ||
| 
						 | 
					1b4a58c95c | ||
| 
						 | 
					bd20abacdf | ||
| 
						 | 
					f0ca087d48 | ||
| 
						 | 
					21bf1ff148 | ||
| 
						 | 
					66c010dd28 | ||
| 
						 | 
					0fb18e8a32 | ||
| 
						 | 
					da21df49ce | ||
| 
						 | 
					54d6565411 | ||
| 
						 | 
					5052a818ff | ||
| 
						 | 
					5e1f3e0e31 | ||
| 
						 | 
					c0740a9760 | ||
| 
						 | 
					88ebeead8c | ||
| 
						 | 
					41c155c332 | ||
| 
						 | 
					aaf6c933b5 | ||
| 
						 | 
					5e58f7ef37 | ||
| 
						 | 
					9fdd0019c1 | ||
| 
						 | 
					f94e4b3aed | ||
| 
						 | 
					b2b183f95c | ||
| 
						 | 
					2cfa5040dc | ||
| 
						 | 
					3112e2ad36 | ||
| 
						 | 
					0e45f3700b | ||
| 
						 | 
					78d9e508fc | ||
| 
						 | 
					81ff75f1cc | ||
| 
						 | 
					ab276bb474 | ||
| 
						 | 
					2a8f09cb46 | ||
| 
						 | 
					239dcffc98 | ||
| 
						 | 
					5fb32934fa | ||
| 
						 | 
					38010d4628 | ||
| 
						 | 
					669f7f3433 | ||
| 
						 | 
					3576d5516f | ||
| 
						 | 
					0781f15bae | ||
| 
						 | 
					e87f4d6476 | ||
| 
						 | 
					dd7d5e8ab6 | ||
| 
						 | 
					776ecabf81 | ||
| 
						 | 
					5c6814852e | ||
| 
						 | 
					90c700702e | ||
| 
						 | 
					7c3ae1b5b9 | ||
| 
						 | 
					15c2f6a4fc | ||
| 
						 | 
					9d5855bc6e | ||
| 
						 | 
					b7d72474da | ||
| 
						 | 
					33650f5cea | ||
| 
						 | 
					e8955454f7 | ||
| 
						 | 
					6e0cf66008 | ||
| 
						 | 
					6d305636a0 | ||
| 
						 | 
					958b3337a8 | ||
| 
						 | 
					3c7fa2ce9e | ||
| 
						 | 
					b6a941197a | ||
| 
						 | 
					338ac586de | ||
| 
						 | 
					69262ee213 | ||
| 
						 | 
					a592534621 | ||
| 
						 | 
					c7e41c6671 | ||
| 
						 | 
					17cecb3a3a | ||
| 
						 | 
					64432c2fcd | ||
| 
						 | 
					b8e98abfbd | ||
| 
						 | 
					da507cb55c | ||
| 
						 | 
					bdf8f642f9 | ||
| 
						 | 
					d6a7ff14e4 | ||
| 
						 | 
					3f3c48b17d | ||
| 
						 | 
					878de17cd6 | ||
| 
						 | 
					c1babcff00 | ||
| 
						 | 
					41ec3b3495 | ||
| 
						 | 
					daa264c984 | ||
| 
						 | 
					17f95a64ad | ||
| 
						 | 
					8fff2ced69 | ||
| 
						 | 
					4bbc4154eb | ||
| 
						 | 
					ffb7dd890e | ||
| 
						 | 
					ce1818c93c | ||
| 
						 | 
					acdb617d35 | ||
| 
						 | 
					b0f1ecbbe4 | ||
| 
						 | 
					040c782f3b | ||
| 
						 | 
					2f39ead739 | ||
| 
						 | 
					6312c7b1d8 | ||
| 
						 | 
					0417162858 | ||
| 
						 | 
					75b2b30b67 | ||
| 
						 | 
					abc06d7953 | ||
| 
						 | 
					7993e7d345 | ||
| 
						 | 
					be4549fabb | ||
| 
						 | 
					92c141e511 | ||
| 
						 | 
					296713e853 | ||
| 
						 | 
					d6dee68880 | ||
| 
						 | 
					aaffa145ad | ||
| 
						 | 
					c8e894bf79 | ||
| 
						 | 
					766a608e1b | ||
| 
						 | 
					333316d7a9 | ||
| 
						 | 
					6527b45f2f | ||
| 
						 | 
					76ef41aefe | ||
| 
						 | 
					7e988c5780 | ||
| 
						 | 
					2080027d7c | ||
| 
						 | 
					b8a14e95d8 | ||
| 
						 | 
					8966888e6b | ||
| 
						 | 
					0ad79b8076 | ||
| 
						 | 
					f650a6fde4 | ||
| 
						 | 
					a6b7057c9b | ||
| 
						 | 
					6a1fa01235 | ||
| 
						 | 
					f554e73b91 | ||
| 
						 | 
					2316dca6ce | ||
| 
						 | 
					2395423832 | ||
| 
						 | 
					43363e6854 | ||
| 
						 | 
					2ab3d6a53d | ||
| 
						 | 
					561fc84958 | ||
| 
						 | 
					afbe50b65d | ||
| 
						 | 
					15b5551cd8 | ||
| 
						 | 
					717ab7451f | ||
| 
						 | 
					8afba9650b | ||
| 
						 | 
					155d6ba319 | ||
| 
						 | 
					66f4742ca5 | ||
| 
						 | 
					ad1bc551db | ||
| 
						 | 
					9926b551f5 | ||
| 
						 | 
					1dfd7969ea | ||
| 
						 | 
					a62e34fdf8 | ||
| 
						 | 
					45deeaea88 | ||
| 
						 | 
					c5aadffe1d | ||
| 
						 | 
					d10883b60d | ||
| 
						 | 
					d38db8e05b | ||
| 
						 | 
					8ea43f455c | ||
| 
						 | 
					f653083548 | ||
| 
						 | 
					66c50b27bf | ||
| 
						 | 
					351dd650fa | ||
| 
						 | 
					8550675c04 | ||
| 
						 | 
					76864c21d7 | ||
| 
						 | 
					696ee32ef3 | ||
| 
						 | 
					780d6654fb | ||
| 
						 | 
					b195763518 | ||
| 
						 | 
					6543f44eab | ||
| 
						 | 
					9b5aa5dd5d | ||
| 
						 | 
					3062424816 | ||
| 
						 | 
					41bd759d03 | ||
| 
						 | 
					a27cd109e8 | ||
| 
						 | 
					ec03bc6710 | ||
| 
						 | 
					f00de63289 | ||
| 
						 | 
					becd374124 | ||
| 
						 | 
					89256bb900 | ||
| 
						 | 
					a1634770bc | ||
| 
						 | 
					6db6e51ef3 | ||
| 
						 | 
					1ada42bdcb | ||
| 
						 | 
					6bbcca57ae | ||
| 
						 | 
					447ab2a705 | ||
| 
						 | 
					ae251f9d35 | ||
| 
						 | 
					729b1e6708 | ||
| 
						 | 
					514bb3e622 | ||
| 
						 | 
					087265b8b7 | ||
| 
						 | 
					ccd5498f19 | ||
| 
						 | 
					1688f5a39d | ||
| 
						 | 
					1b185515ce | ||
| 
						 | 
					3c45f07cee | ||
| 
						 | 
					a493c9190e | ||
| 
						 | 
					fda8afd90c | ||
| 
						 | 
					a18cb37671 | ||
| 
						 | 
					2c85a691bb | ||
| 
						 | 
					e8800782b4 | ||
| 
						 | 
					d0e818805a | ||
| 
						 | 
					02ad85ca73 | ||
| 
						 | 
					0ca578e9ec | ||
| 
						 | 
					d351522441 | ||
| 
						 | 
					401419e060 | ||
| 
						 | 
					a8b0b46b1a | ||
| 
						 | 
					d4fe199b0d | ||
| 
						 | 
					52bbf884f9 | 
							
								
								
									
										178
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					Language:        Cpp
 | 
				
			||||||
 | 
					# BasedOnStyle:  LLVM
 | 
				
			||||||
 | 
					AccessModifierOffset: -2
 | 
				
			||||||
 | 
					AlignAfterOpenBracket: Align
 | 
				
			||||||
 | 
					AlignArrayOfStructures: None
 | 
				
			||||||
 | 
					AlignConsecutiveMacros: None
 | 
				
			||||||
 | 
					AlignConsecutiveAssignments: None
 | 
				
			||||||
 | 
					AlignConsecutiveBitFields: None
 | 
				
			||||||
 | 
					AlignConsecutiveDeclarations: None
 | 
				
			||||||
 | 
					AlignEscapedNewlines: Right
 | 
				
			||||||
 | 
					AlignOperands:   Align
 | 
				
			||||||
 | 
					AlignTrailingComments: true
 | 
				
			||||||
 | 
					AllowAllArgumentsOnNextLine: true
 | 
				
			||||||
 | 
					AllowAllConstructorInitializersOnNextLine: true
 | 
				
			||||||
 | 
					AllowAllParametersOfDeclarationOnNextLine: true
 | 
				
			||||||
 | 
					AllowShortEnumsOnASingleLine: true
 | 
				
			||||||
 | 
					AllowShortBlocksOnASingleLine: Never
 | 
				
			||||||
 | 
					AllowShortCaseLabelsOnASingleLine: false
 | 
				
			||||||
 | 
					AllowShortFunctionsOnASingleLine: All
 | 
				
			||||||
 | 
					AllowShortLambdasOnASingleLine: All
 | 
				
			||||||
 | 
					AllowShortIfStatementsOnASingleLine: Never
 | 
				
			||||||
 | 
					AllowShortLoopsOnASingleLine: false
 | 
				
			||||||
 | 
					AlwaysBreakAfterDefinitionReturnType: None
 | 
				
			||||||
 | 
					AlwaysBreakAfterReturnType: None
 | 
				
			||||||
 | 
					AlwaysBreakBeforeMultilineStrings: false
 | 
				
			||||||
 | 
					AlwaysBreakTemplateDeclarations: MultiLine
 | 
				
			||||||
 | 
					AttributeMacros:
 | 
				
			||||||
 | 
					  - __capability
 | 
				
			||||||
 | 
					BinPackArguments: true
 | 
				
			||||||
 | 
					BinPackParameters: true
 | 
				
			||||||
 | 
					BraceWrapping:
 | 
				
			||||||
 | 
					  AfterCaseLabel:  false
 | 
				
			||||||
 | 
					  AfterClass:      false
 | 
				
			||||||
 | 
					  AfterControlStatement: Never
 | 
				
			||||||
 | 
					  AfterEnum:       false
 | 
				
			||||||
 | 
					  AfterFunction:   false
 | 
				
			||||||
 | 
					  AfterNamespace:  false
 | 
				
			||||||
 | 
					  AfterObjCDeclaration: false
 | 
				
			||||||
 | 
					  AfterStruct:     false
 | 
				
			||||||
 | 
					  AfterUnion:      false
 | 
				
			||||||
 | 
					  AfterExternBlock: false
 | 
				
			||||||
 | 
					  BeforeCatch:     false
 | 
				
			||||||
 | 
					  BeforeElse:      false
 | 
				
			||||||
 | 
					  BeforeLambdaBody: false
 | 
				
			||||||
 | 
					  BeforeWhile:     false
 | 
				
			||||||
 | 
					  IndentBraces:    false
 | 
				
			||||||
 | 
					  SplitEmptyFunction: true
 | 
				
			||||||
 | 
					  SplitEmptyRecord: true
 | 
				
			||||||
 | 
					  SplitEmptyNamespace: true
 | 
				
			||||||
 | 
					BreakBeforeBinaryOperators: None
 | 
				
			||||||
 | 
					BreakBeforeConceptDeclarations: true
 | 
				
			||||||
 | 
					BreakBeforeBraces: Attach
 | 
				
			||||||
 | 
					BreakBeforeInheritanceComma: false
 | 
				
			||||||
 | 
					BreakInheritanceList: BeforeColon
 | 
				
			||||||
 | 
					BreakBeforeTernaryOperators: true
 | 
				
			||||||
 | 
					BreakConstructorInitializersBeforeComma: false
 | 
				
			||||||
 | 
					BreakConstructorInitializers: BeforeColon
 | 
				
			||||||
 | 
					BreakAfterJavaFieldAnnotations: false
 | 
				
			||||||
 | 
					BreakStringLiterals: true
 | 
				
			||||||
 | 
					ColumnLimit:     100
 | 
				
			||||||
 | 
					CommentPragmas:  '^ IWYU pragma:'
 | 
				
			||||||
 | 
					CompactNamespaces: false
 | 
				
			||||||
 | 
					ConstructorInitializerAllOnOneLineOrOnePerLine: false
 | 
				
			||||||
 | 
					ConstructorInitializerIndentWidth: 4
 | 
				
			||||||
 | 
					ContinuationIndentWidth: 4
 | 
				
			||||||
 | 
					Cpp11BracedListStyle: true
 | 
				
			||||||
 | 
					DeriveLineEnding: true
 | 
				
			||||||
 | 
					DerivePointerAlignment: false
 | 
				
			||||||
 | 
					DisableFormat:   false
 | 
				
			||||||
 | 
					EmptyLineAfterAccessModifier: Never
 | 
				
			||||||
 | 
					EmptyLineBeforeAccessModifier: LogicalBlock
 | 
				
			||||||
 | 
					ExperimentalAutoDetectBinPacking: false
 | 
				
			||||||
 | 
					FixNamespaceComments: true
 | 
				
			||||||
 | 
					ForEachMacros:
 | 
				
			||||||
 | 
					  - foreach
 | 
				
			||||||
 | 
					  - Q_FOREACH
 | 
				
			||||||
 | 
					  - BOOST_FOREACH
 | 
				
			||||||
 | 
					IfMacros:
 | 
				
			||||||
 | 
					  - KJ_IF_MAYBE
 | 
				
			||||||
 | 
					IncludeBlocks:   Preserve
 | 
				
			||||||
 | 
					IncludeCategories:
 | 
				
			||||||
 | 
					  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
 | 
				
			||||||
 | 
					    Priority:        2
 | 
				
			||||||
 | 
					    SortPriority:    0
 | 
				
			||||||
 | 
					    CaseSensitive:   false
 | 
				
			||||||
 | 
					  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
 | 
				
			||||||
 | 
					    Priority:        3
 | 
				
			||||||
 | 
					    SortPriority:    0
 | 
				
			||||||
 | 
					    CaseSensitive:   false
 | 
				
			||||||
 | 
					  - Regex:           '.*'
 | 
				
			||||||
 | 
					    Priority:        1
 | 
				
			||||||
 | 
					    SortPriority:    0
 | 
				
			||||||
 | 
					    CaseSensitive:   false
 | 
				
			||||||
 | 
					IncludeIsMainRegex: '(Test)?$'
 | 
				
			||||||
 | 
					IncludeIsMainSourceRegex: ''
 | 
				
			||||||
 | 
					IndentAccessModifiers: false
 | 
				
			||||||
 | 
					IndentCaseLabels: false
 | 
				
			||||||
 | 
					IndentCaseBlocks: false
 | 
				
			||||||
 | 
					IndentGotoLabels: true
 | 
				
			||||||
 | 
					IndentPPDirectives: None
 | 
				
			||||||
 | 
					IndentExternBlock: AfterExternBlock
 | 
				
			||||||
 | 
					IndentRequires:  false
 | 
				
			||||||
 | 
					IndentWidth:     4
 | 
				
			||||||
 | 
					IndentWrappedFunctionNames: false
 | 
				
			||||||
 | 
					InsertTrailingCommas: None
 | 
				
			||||||
 | 
					JavaScriptQuotes: Leave
 | 
				
			||||||
 | 
					JavaScriptWrapImports: true
 | 
				
			||||||
 | 
					KeepEmptyLinesAtTheStartOfBlocks: true
 | 
				
			||||||
 | 
					LambdaBodyIndentation: Signature
 | 
				
			||||||
 | 
					MacroBlockBegin: ''
 | 
				
			||||||
 | 
					MacroBlockEnd:   ''
 | 
				
			||||||
 | 
					MaxEmptyLinesToKeep: 1
 | 
				
			||||||
 | 
					NamespaceIndentation: All
 | 
				
			||||||
 | 
					ObjCBinPackProtocolList: Auto
 | 
				
			||||||
 | 
					ObjCBlockIndentWidth: 2
 | 
				
			||||||
 | 
					ObjCBreakBeforeNestedBlockParam: true
 | 
				
			||||||
 | 
					ObjCSpaceAfterProperty: false
 | 
				
			||||||
 | 
					ObjCSpaceBeforeProtocolList: true
 | 
				
			||||||
 | 
					PenaltyBreakAssignment: 2
 | 
				
			||||||
 | 
					PenaltyBreakBeforeFirstCallParameter: 19
 | 
				
			||||||
 | 
					PenaltyBreakComment: 300
 | 
				
			||||||
 | 
					PenaltyBreakFirstLessLess: 120
 | 
				
			||||||
 | 
					PenaltyBreakString: 1000
 | 
				
			||||||
 | 
					PenaltyBreakTemplateDeclaration: 10
 | 
				
			||||||
 | 
					PenaltyExcessCharacter: 1000000
 | 
				
			||||||
 | 
					PenaltyReturnTypeOnItsOwnLine: 60
 | 
				
			||||||
 | 
					PenaltyIndentedWhitespace: 0
 | 
				
			||||||
 | 
					PointerAlignment: Right
 | 
				
			||||||
 | 
					PPIndentWidth:   -1
 | 
				
			||||||
 | 
					ReferenceAlignment: Pointer
 | 
				
			||||||
 | 
					ReflowComments:  true
 | 
				
			||||||
 | 
					ShortNamespaceLines: 1
 | 
				
			||||||
 | 
					SortIncludes:    CaseSensitive
 | 
				
			||||||
 | 
					SortJavaStaticImport: Before
 | 
				
			||||||
 | 
					SortUsingDeclarations: true
 | 
				
			||||||
 | 
					SpaceAfterCStyleCast: false
 | 
				
			||||||
 | 
					SpaceAfterLogicalNot: false
 | 
				
			||||||
 | 
					SpaceAfterTemplateKeyword: true
 | 
				
			||||||
 | 
					SpaceBeforeAssignmentOperators: true
 | 
				
			||||||
 | 
					SpaceBeforeCaseColon: false
 | 
				
			||||||
 | 
					SpaceBeforeCpp11BracedList: false
 | 
				
			||||||
 | 
					SpaceBeforeCtorInitializerColon: true
 | 
				
			||||||
 | 
					SpaceBeforeInheritanceColon: true
 | 
				
			||||||
 | 
					SpaceBeforeParens: ControlStatements
 | 
				
			||||||
 | 
					SpaceAroundPointerQualifiers: Default
 | 
				
			||||||
 | 
					SpaceBeforeRangeBasedForLoopColon: true
 | 
				
			||||||
 | 
					SpaceInEmptyBlock: false
 | 
				
			||||||
 | 
					SpaceInEmptyParentheses: false
 | 
				
			||||||
 | 
					SpacesBeforeTrailingComments: 1
 | 
				
			||||||
 | 
					SpacesInAngles:  Never
 | 
				
			||||||
 | 
					SpacesInConditionalStatement: false
 | 
				
			||||||
 | 
					SpacesInContainerLiterals: true
 | 
				
			||||||
 | 
					SpacesInCStyleCastParentheses: false
 | 
				
			||||||
 | 
					SpacesInLineCommentPrefix:
 | 
				
			||||||
 | 
					  Minimum:         1
 | 
				
			||||||
 | 
					  Maximum:         -1
 | 
				
			||||||
 | 
					SpacesInParentheses: false
 | 
				
			||||||
 | 
					SpacesInSquareBrackets: false
 | 
				
			||||||
 | 
					SpaceBeforeSquareBrackets: false
 | 
				
			||||||
 | 
					BitFieldColonSpacing: Both
 | 
				
			||||||
 | 
					Standard:        Latest
 | 
				
			||||||
 | 
					StatementAttributeLikeMacros:
 | 
				
			||||||
 | 
					  - Q_EMIT
 | 
				
			||||||
 | 
					StatementMacros:
 | 
				
			||||||
 | 
					  - Q_UNUSED
 | 
				
			||||||
 | 
					  - QT_REQUIRE_VERSION
 | 
				
			||||||
 | 
					TabWidth:        4
 | 
				
			||||||
 | 
					UseCRLF:         false
 | 
				
			||||||
 | 
					UseTab:          Always
 | 
				
			||||||
 | 
					WhitespaceSensitiveMacros:
 | 
				
			||||||
 | 
					  - STRINGIZE
 | 
				
			||||||
 | 
					  - PP_STRINGIZE
 | 
				
			||||||
 | 
					  - BOOST_PP_STRINGIZE
 | 
				
			||||||
 | 
					  - NS_SWIFT_NAME
 | 
				
			||||||
 | 
					  - CF_SWIFT_NAME
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -27,7 +27,7 @@ jobs:
 | 
				
			|||||||
      DOCKER_REGISTRY_USERNAME: ucentral
 | 
					      DOCKER_REGISTRY_USERNAME: ucentral
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Checkout actions repo
 | 
					    - name: Checkout actions repo
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        repository: Telecominfraproject/.github
 | 
					        repository: Telecominfraproject/.github
 | 
				
			||||||
        path: github
 | 
					        path: github
 | 
				
			||||||
@@ -58,11 +58,11 @@ jobs:
 | 
				
			|||||||
    - name: Get base branch name and set as output
 | 
					    - name: Get base branch name and set as output
 | 
				
			||||||
      id: get_base_branch
 | 
					      id: get_base_branch
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
 | 
					        echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT
 | 
				
			||||||
        echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
 | 
					        echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Checkout actions repo
 | 
					    - name: Checkout actions repo
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        repository: Telecominfraproject/.github
 | 
					        repository: Telecominfraproject/.github
 | 
				
			||||||
        path: github
 | 
					        path: github
 | 
				
			||||||
@@ -87,7 +87,7 @@ jobs:
 | 
				
			|||||||
      - docker
 | 
					      - docker
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Checkout actions repo
 | 
					    - name: Checkout actions repo
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        repository: Telecominfraproject/.github
 | 
					        repository: Telecominfraproject/.github
 | 
				
			||||||
        path: github
 | 
					        path: github
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -11,7 +11,7 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout actions repo
 | 
					      - name: Checkout actions repo
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          repository: Telecominfraproject/.github
 | 
					          repository: Telecominfraproject/.github
 | 
				
			||||||
          path: github
 | 
					          path: github
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								.github/workflows/openapi-pages.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					name: Update OpenAPI docs on GitHub Pages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - 'openapi/**'
 | 
				
			||||||
 | 
					    branches:
 | 
				
			||||||
 | 
					      - main
 | 
				
			||||||
 | 
					  workflow_dispatch:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaults:
 | 
				
			||||||
 | 
					  run:
 | 
				
			||||||
 | 
					    shell: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  docsgen:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - uses: actions/checkout@v3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Generate static HTML page with docs from OpenAPI definition
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openpapi/owsec.yaml -g html2 --skip-validate-spec -o /local/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Update OpenAPI docs
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          mkdir -p ~/.ssh
 | 
				
			||||||
 | 
					          ssh-keyscan -H github.com >> ~/.ssh/known_hosts
 | 
				
			||||||
 | 
					          echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
 | 
				
			||||||
 | 
					          git config --global credential.helper store
 | 
				
			||||||
 | 
					          git config --global user.email "tip-automation@telecominfraproject.com"
 | 
				
			||||||
 | 
					          git config --global user.name "TIP Automation User"
 | 
				
			||||||
 | 
					          git pull
 | 
				
			||||||
 | 
					          git checkout gh-pages || git checkout -b gh-pages
 | 
				
			||||||
 | 
					          mv index.html docs/index.html
 | 
				
			||||||
 | 
					          git add docs
 | 
				
			||||||
 | 
					          git commit -m'Update OpenAPI docs for GitHub pages'
 | 
				
			||||||
 | 
					          git push --set-upstream origin gh-pages
 | 
				
			||||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -17,7 +17,7 @@ jobs:
 | 
				
			|||||||
      HELM_REPO_USERNAME: ucentral
 | 
					      HELM_REPO_USERNAME: ucentral
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout uCentral assembly chart repo
 | 
					      - name: Checkout uCentral assembly chart repo
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          path: wlan-cloud-ucentralsec
 | 
					          path: wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						@@ -1,21 +0,0 @@
 | 
				
			|||||||
# Default ignored files
 | 
					 | 
				
			||||||
/shelf/
 | 
					 | 
				
			||||||
/workspace.xml
 | 
					 | 
				
			||||||
# Datasource local storage ignored files
 | 
					 | 
				
			||||||
/dataSources/
 | 
					 | 
				
			||||||
/dataSources.local.xml
 | 
					 | 
				
			||||||
# Editor-based HTTP Client requests
 | 
					 | 
				
			||||||
/httpRequests/
 | 
					 | 
				
			||||||
/certs/
 | 
					 | 
				
			||||||
/logs/
 | 
					 | 
				
			||||||
*.csr
 | 
					 | 
				
			||||||
*.db
 | 
					 | 
				
			||||||
/docker-compose/certs/
 | 
					 | 
				
			||||||
/docker-compose/*-data/data/
 | 
					 | 
				
			||||||
/docker-compose/*-data/uploads/
 | 
					 | 
				
			||||||
/docker-compose/.env
 | 
					 | 
				
			||||||
/docker-compose/.env_*
 | 
					 | 
				
			||||||
/cmake-build/
 | 
					 | 
				
			||||||
*.pem
 | 
					 | 
				
			||||||
result.json
 | 
					 | 
				
			||||||
token.json
 | 
					 | 
				
			||||||
							
								
								
									
										197
									
								
								BUILDING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,197 @@
 | 
				
			|||||||
 | 
					# Building from source
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to build OWSEC, you will need to install its dependencies, which includes the following:
 | 
				
			||||||
 | 
					- cmake
 | 
				
			||||||
 | 
					- boost
 | 
				
			||||||
 | 
					- POCO 1.10.1 or later
 | 
				
			||||||
 | 
					- a C++17 compiler
 | 
				
			||||||
 | 
					- openssl
 | 
				
			||||||
 | 
					- libpq-dev (PortgreSQL development libraries)
 | 
				
			||||||
 | 
					- mysql-client (MySQL client)
 | 
				
			||||||
 | 
					- librdkafka
 | 
				
			||||||
 | 
					- cppkafka
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This
 | 
				
			||||||
 | 
					framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
 | 
				
			||||||
 | 
					from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/Telecominfraproject/wlan-cloud-lib-poco). Building
 | 
				
			||||||
 | 
					Poco may take several minutes depending on the platform you are building on.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Ubuntu
 | 
				
			||||||
 | 
					These instructions have proven to work on Ubuntu 20.4.
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					sudo apt install git cmake g++ libssl-dev libmariadb-dev \
 | 
				
			||||||
 | 
					    libpq-dev libaprutil1-dev apache2-dev libboost-all-dev \
 | 
				
			||||||
 | 
					    librdkafka-dev default-libmysqlclient-dev \
 | 
				
			||||||
 | 
					    nlohmann-json-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
 | 
				
			||||||
 | 
					cd poco
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
 | 
				
			||||||
 | 
					cd cppkafka
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
 | 
				
			||||||
 | 
					cd valijson
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
 | 
				
			||||||
 | 
					cd fmtlib
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					make
 | 
				
			||||||
 | 
					make install
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					cd wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					make -j 8
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Fedora
 | 
				
			||||||
 | 
					The following instructions have proven to work on Fedora 33
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel \
 | 
				
			||||||
 | 
					    yaml-cpp-devel lua-devel
 | 
				
			||||||
 | 
					sudo dnf install postgresql.x86_64 librdkafka-devel
 | 
				
			||||||
 | 
					sudo dnf install postgresql-devel json-devel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
 | 
				
			||||||
 | 
					cd poco
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
 | 
				
			||||||
 | 
					cd cppkafka
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
 | 
				
			||||||
 | 
					cd valijson
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					cd wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					make
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## macOS Build
 | 
				
			||||||
 | 
					The following instructions have proven to work on macOS Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/).
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					brew install openssl \
 | 
				
			||||||
 | 
						cmake \
 | 
				
			||||||
 | 
						libpq \
 | 
				
			||||||
 | 
						mysql-client \
 | 
				
			||||||
 | 
						apr \
 | 
				
			||||||
 | 
						apr-util \
 | 
				
			||||||
 | 
						boost \
 | 
				
			||||||
 | 
						yaml-cpp \
 | 
				
			||||||
 | 
						postgresql \
 | 
				
			||||||
 | 
						librdkafka \
 | 
				
			||||||
 | 
						nlohmann-json \
 | 
				
			||||||
 | 
						fmt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
 | 
				
			||||||
 | 
					pushd poco
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					push cmake-build
 | 
				
			||||||
 | 
					cmake -DOPENSSL_ROOT_DIR=</path/to/openssl> -DENABLE_NETSSL=1 -DENABLE_JWT=1 -DENABLE_CRYPTO=1 ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
 | 
				
			||||||
 | 
					pushd cppkafka
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					pushd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
 | 
				
			||||||
 | 
					pushd valijson
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					pushd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					pushd wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					pushd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					make -j
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					popd
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Raspberry
 | 
				
			||||||
 | 
					The build on a rPI takes a while. You can shorten that build time and requirements by disabling all the larger database
 | 
				
			||||||
 | 
					support. You can build with only SQLite support by not installing the packages for PostgreSQL, and MySQL by
 | 
				
			||||||
 | 
					adding -DSMALL_BUILD=1 on the cmake build line.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev \
 | 
				
			||||||
 | 
					    libboost-all-dev libyaml-cpp-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
 | 
				
			||||||
 | 
					cd poco
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					sudo cmake --build . --target install
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					cd wlan-cloud-ucentralsec
 | 
				
			||||||
 | 
					mkdir cmake-build
 | 
				
			||||||
 | 
					cd cmake-build
 | 
				
			||||||
 | 
					cmake -DSMALL_BUILD=1 ..
 | 
				
			||||||
 | 
					make
 | 
				
			||||||
 | 
					cd ../..
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.13)
 | 
					cmake_minimum_required(VERSION 3.13)
 | 
				
			||||||
project(owsec VERSION 2.7.0)
 | 
					project(owsec VERSION 3.2.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_CXX_STANDARD 17)
 | 
					set(CMAKE_CXX_STANDARD 17)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,17 +32,17 @@ endif()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
find_package(Git QUIET)
 | 
					find_package(Git QUIET)
 | 
				
			||||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
 | 
					if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
 | 
				
			||||||
    execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
 | 
					    execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
 | 
				
			||||||
            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
					            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
				
			||||||
            RESULT_VARIABLE GIT_RESULT
 | 
					            RESULT_VARIABLE GIT_RESULT
 | 
				
			||||||
            OUTPUT_VARIABLE GIT_HASH)
 | 
					            OUTPUT_VARIABLE GIT_HASH)
 | 
				
			||||||
    if(NOT GIT_RESULT EQUAL "0")
 | 
					    if(NOT GIT_RESULT EQUAL "0")
 | 
				
			||||||
        message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
 | 
					        message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
 | 
				
			||||||
    endif()
 | 
					    endif()
 | 
				
			||||||
    string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
 | 
					    string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
 | 
					add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT -DBOOST_NO_CXX98_FUNCTION_BASE=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(BUILD_SHARED_LIBS 1)
 | 
					set(BUILD_SHARED_LIBS 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,19 +75,63 @@ add_executable( owsec
 | 
				
			|||||||
        src/framework/CountryCodes.h
 | 
					        src/framework/CountryCodes.h
 | 
				
			||||||
        src/framework/KafkaTopics.h
 | 
					        src/framework/KafkaTopics.h
 | 
				
			||||||
        src/framework/MicroService.h
 | 
					        src/framework/MicroService.h
 | 
				
			||||||
 | 
					        src/framework/OpenWifiTypes.h
 | 
				
			||||||
        src/framework/orm.h
 | 
					        src/framework/orm.h
 | 
				
			||||||
        src/framework/StorageClass.h
 | 
					        src/framework/StorageClass.h
 | 
				
			||||||
        src/framework/ow_constants.h
 | 
					 | 
				
			||||||
        src/framework/MicroServiceErrorHandler.h
 | 
					        src/framework/MicroServiceErrorHandler.h
 | 
				
			||||||
        src/framework/WebSocketClientNotifications.h
 | 
					        src/framework/UI_WebSocketClientServer.cpp
 | 
				
			||||||
 | 
					        src/framework/UI_WebSocketClientServer.h
 | 
				
			||||||
 | 
					        src/framework/UI_WebSocketClientNotifications.cpp
 | 
				
			||||||
 | 
					        src/framework/UI_WebSocketClientNotifications.h
 | 
				
			||||||
 | 
					        src/framework/utils.h
 | 
				
			||||||
 | 
					        src/framework/utils.cpp
 | 
				
			||||||
 | 
					        src/framework/AppServiceRegistry.h
 | 
				
			||||||
 | 
					        src/framework/SubSystemServer.cpp
 | 
				
			||||||
 | 
					        src/framework/SubSystemServer.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_utils.h
 | 
				
			||||||
 | 
					        src/framework/AuthClient.cpp
 | 
				
			||||||
 | 
					        src/framework/AuthClient.h
 | 
				
			||||||
 | 
					        src/framework/MicroServiceNames.h
 | 
				
			||||||
 | 
					        src/framework/MicroServiceFuncs.h
 | 
				
			||||||
 | 
					        src/framework/OpenAPIRequests.cpp
 | 
				
			||||||
 | 
					        src/framework/OpenAPIRequests.h
 | 
				
			||||||
 | 
					        src/framework/MicroServiceFuncs.cpp
 | 
				
			||||||
 | 
					        src/framework/ALBserver.cpp
 | 
				
			||||||
 | 
					        src/framework/ALBserver.h
 | 
				
			||||||
 | 
					        src/framework/KafkaManager.cpp
 | 
				
			||||||
 | 
					        src/framework/KafkaManager.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_RateLimiter.h
 | 
				
			||||||
 | 
					        src/framework/WebSocketLogger.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_GenericServerAccounting.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_SystemConfiguration.h
 | 
				
			||||||
 | 
					        src/framework/CIDR.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_Handler.cpp
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_Handler.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_ExtServer.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_ExtServer.cpp
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_IntServer.cpp
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_IntServer.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_SystemCommand.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_WebSocketServer.h
 | 
				
			||||||
 | 
					        src/framework/EventBusManager.cpp
 | 
				
			||||||
 | 
					        src/framework/EventBusManager.h
 | 
				
			||||||
 | 
					        src/framework/RESTAPI_PartHandler.h
 | 
				
			||||||
 | 
					        src/framework/MicroService.cpp
 | 
				
			||||||
 | 
					        src/framework/MicroServiceExtra.h
 | 
				
			||||||
 | 
					        src/framework/default_device_types.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
 | 
				
			||||||
 | 
					        src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        src/seclibs/qrcode/qrcodegen.hpp src/seclibs/qrcode/qrcodegen.cpp
 | 
					        src/seclibs/qrcode/qrcodegen.hpp src/seclibs/qrcode/qrcodegen.cpp
 | 
				
			||||||
        src/seclibs/cpptotp/bytes.cpp src/seclibs/cpptotp/bytes.h
 | 
					        src/seclibs/cpptotp/bytes.cpp src/seclibs/cpptotp/bytes.h
 | 
				
			||||||
        src/seclibs/cpptotp/otp.cpp src/seclibs/cpptotp/otp.h
 | 
					        src/seclibs/cpptotp/otp.cpp src/seclibs/cpptotp/otp.h
 | 
				
			||||||
        src/seclibs/cpptotp/sha1.cpp src/seclibs/cpptotp/sha1.h
 | 
					        src/seclibs/cpptotp/sha1.cpp src/seclibs/cpptotp/sha1.h
 | 
				
			||||||
        src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
 | 
					 | 
				
			||||||
        src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
 | 
					 | 
				
			||||||
        src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
 | 
					 | 
				
			||||||
        src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
 | 
					 | 
				
			||||||
        src/RESTAPI/RESTAPI_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp
 | 
					        src/RESTAPI/RESTAPI_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp
 | 
				
			||||||
        src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
 | 
					        src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
 | 
				
			||||||
        src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h
 | 
					        src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h
 | 
				
			||||||
@@ -119,14 +163,19 @@ add_executable( owsec
 | 
				
			|||||||
        src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
 | 
					        src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
 | 
				
			||||||
        src/ActionLinkManager.cpp src/ActionLinkManager.h
 | 
					        src/ActionLinkManager.cpp src/ActionLinkManager.h
 | 
				
			||||||
        src/ACLProcessor.h
 | 
					        src/ACLProcessor.h
 | 
				
			||||||
        src/framework/OpenWifiTypes.h
 | 
					 | 
				
			||||||
        src/storage/orm_users.cpp src/storage/orm_users.h
 | 
					        src/storage/orm_users.cpp src/storage/orm_users.h
 | 
				
			||||||
        src/storage/orm_tokens.cpp src/storage/orm_tokens.h
 | 
					        src/storage/orm_tokens.cpp src/storage/orm_tokens.h
 | 
				
			||||||
        src/storage/orm_preferences.cpp src/storage/orm_preferences.h
 | 
					        src/storage/orm_preferences.cpp src/storage/orm_preferences.h
 | 
				
			||||||
        src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
 | 
					        src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
 | 
				
			||||||
        src/storage/orm_avatar.cpp src/storage/orm_avatar.h
 | 
					        src/storage/orm_avatar.cpp src/storage/orm_avatar.h
 | 
				
			||||||
        src/SpecialUserHelpers.h
 | 
					        src/SpecialUserHelpers.h
 | 
				
			||||||
        src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h src/MessagingTemplates.cpp src/MessagingTemplates.h)
 | 
					        src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_totp_handler.cpp
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_totp_handler.h
 | 
				
			||||||
 | 
					        src/TotpCache.h
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h
 | 
				
			||||||
 | 
					        src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h
 | 
				
			||||||
 | 
					        src/MessagingTemplates.h src/RESTAPI/RESTAPI_apiKey_handler.cpp src/RESTAPI/RESTAPI_apiKey_handler.h src/storage/orm_apikeys.cpp src/storage/orm_apikeys.h src/RESTAPI/RESTAPI_validate_apikey.cpp src/RESTAPI/RESTAPI_validate_apikey.h src/RESTAPI/RESTAPI_systemSecret_handler.cpp src/RESTAPI/RESTAPI_systemSecret_handler.h src/SecretStore.cpp src/SecretStore.h)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if(NOT SMALL_BUILD)
 | 
					if(NOT SMALL_BUILD)
 | 
				
			||||||
    target_link_libraries(owsec PUBLIC
 | 
					    target_link_libraries(owsec PUBLIC
 | 
				
			||||||
@@ -136,6 +185,7 @@ if(NOT SMALL_BUILD)
 | 
				
			|||||||
            CppKafka::cppkafka
 | 
					            CppKafka::cppkafka
 | 
				
			||||||
            ${AWSSDK_LINK_LIBRARIES}
 | 
					            ${AWSSDK_LINK_LIBRARIES}
 | 
				
			||||||
            fmt::fmt
 | 
					            fmt::fmt
 | 
				
			||||||
 | 
					            resolv
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
    if(UNIX AND NOT APPLE)
 | 
					    if(UNIX AND NOT APPLE)
 | 
				
			||||||
        target_link_libraries(owsec PUBLIC PocoJSON)
 | 
					        target_link_libraries(owsec PUBLIC PocoJSON)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										270
									
								
								CONFIGURATION.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,270 @@
 | 
				
			|||||||
 | 
					# OWSEC Configuration
 | 
				
			||||||
 | 
					Here is the list of parameters you can configure in the `owsec.properties` file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## OWSEC Specific Parameters
 | 
				
			||||||
 | 
					### OWSEC Login
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					authentication.default.password: 13268b7daa751240369d125e79c873bd8dd3bef7981bdfd38ea03dbb1fbe7dcf
 | 
				
			||||||
 | 
					authentication.default.username: tip@ucentral.com
 | 
				
			||||||
 | 
					authentication.enabled: true
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					authentication.token.ageing = 30 * 24 * 60 * 60
 | 
				
			||||||
 | 
					authentication.oldpasswords = 5
 | 
				
			||||||
 | 
					openwifi.document.policy.access = /wwwassets/access_policy.html
 | 
				
			||||||
 | 
					openwifi.document.policy.password = /wwwassets/password_policy.html
 | 
				
			||||||
 | 
					authentication.validation.expression =
 | 
				
			||||||
 | 
					subscriber.validation.expression =
 | 
				
			||||||
 | 
					subscriber.policy.access = /wwwassets/access_policy.html
 | 
				
			||||||
 | 
					subscriber.policy.password = /wwwassets/password_policy.html
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Mail template variables
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					helper.user.email = charles.bourque@arilia.com
 | 
				
			||||||
 | 
					helper.sub.email = charles.bourque@arilia.com
 | 
				
			||||||
 | 
					helper.user.global.email = info@arilia.com
 | 
				
			||||||
 | 
					helper.sub.global.email = info@arilia.com
 | 
				
			||||||
 | 
					helper.user.site = https://ucentral.dpaas.arilia.com
 | 
				
			||||||
 | 
					helper.sub.site = https://ucentral.dpaas.arilia.com
 | 
				
			||||||
 | 
					helper.user.login = https://ucentral.dpaas.arilia.com
 | 
				
			||||||
 | 
					helper.sub.login = https://ucentral.dpaas.arilia.com
 | 
				
			||||||
 | 
					helper.user.signature = Arilia Wireless Inc.
 | 
				
			||||||
 | 
					helper.sub.signature = Arilia Wireless Inc.
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Google authenticator
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					totp.issuer: Arilia
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Mailer 
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					mailer.enabled: true
 | 
				
			||||||
 | 
					mailer.hostname: email-smtp.us-west-2.amazonaws.com
 | 
				
			||||||
 | 
					mailer.loginmethod: login
 | 
				
			||||||
 | 
					mailer.password: ***********************************************
 | 
				
			||||||
 | 
					mailer.port: 587
 | 
				
			||||||
 | 
					mailer.sender: no-reply@arilia.com
 | 
				
			||||||
 | 
					mailer.templates: $OWSEC_ROOT/templates
 | 
				
			||||||
 | 
					mailer.username: AKIATXEXGKF3QZN543VS
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Built-in web server 
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.avatar.maxsize: 2000000
 | 
				
			||||||
 | 
					openwifi.document.policy.access: /wwwassets/access_policy.html
 | 
				
			||||||
 | 
					openwifi.document.policy.password: /wwwassets/password_policy.html
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### SMS Sender
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					smssender.aws.accesskey: ***********************
 | 
				
			||||||
 | 
					smssender.aws.region: us-west-2
 | 
				
			||||||
 | 
					smssender.aws.secretkey: ******************************************+X
 | 
				
			||||||
 | 
					smssender.enabled: true
 | 
				
			||||||
 | 
					smssender.provider: aws
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					smssender.provider = twilio
 | 
				
			||||||
 | 
					smssender.twilio.sid = ***********************
 | 
				
			||||||
 | 
					smssender.twilio.token = **********************
 | 
				
			||||||
 | 
					smssender.twilio.phonenumber = +18888888888
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Generic OpenWiFi SDK parameters
 | 
				
			||||||
 | 
					### REST API External parameters
 | 
				
			||||||
 | 
					These are the parameters required for the configuration of the external facing REST API server
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.backlog = 100
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.security = relaxed
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.address = *
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.port = 16001
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
				
			||||||
 | 
					openwifi.restapi.host.0.key.password = mypassword
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.backlog
 | 
				
			||||||
 | 
					This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.rootca
 | 
				
			||||||
 | 
					This is the root file of your own certificate CA in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.cert
 | 
				
			||||||
 | 
					This is your own server certificate in `pem` format..
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.key
 | 
				
			||||||
 | 
					This is the private key associated with your own certificate in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.address
 | 
				
			||||||
 | 
					Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.port
 | 
				
			||||||
 | 
					The port on which the REST API server is listening. By default, this is 16002.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.security
 | 
				
			||||||
 | 
					Leave this as `relaxed` for now for devices.
 | 
				
			||||||
 | 
					#### openwifi.restapi.host.0.key.password
 | 
				
			||||||
 | 
					If you key file uses a password, please enter it here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### REST API Intra microservice parameters
 | 
				
			||||||
 | 
					The following parameters describe the configuration for the inter-microservice HTTP server. You may use the same certificate/key
 | 
				
			||||||
 | 
					you are using for your extenral server or another certificate.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.backlog = 100
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.security = relaxed
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.address = *
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.port = 17001
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
				
			||||||
 | 
					openwifi.internal.restapi.host.0.key.password = mypassword
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.backlog
 | 
				
			||||||
 | 
					This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.rootca
 | 
				
			||||||
 | 
					This is the root file of your own certificate CA in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.cert
 | 
				
			||||||
 | 
					This is your own server certificate in `pem` format..
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.key
 | 
				
			||||||
 | 
					This is the private key associated with your own certificate in `pem` format.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.address
 | 
				
			||||||
 | 
					Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.port
 | 
				
			||||||
 | 
					The port on which the REST API server is listening. By default, this is 17002.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.security
 | 
				
			||||||
 | 
					Leave this as `relaxed` for now for devices.
 | 
				
			||||||
 | 
					#### openwifi.internal.host.0.key.password
 | 
				
			||||||
 | 
					If you key file uses a password, please enter it here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Microservice information
 | 
				
			||||||
 | 
					These are different Microservie parameters. Following is a brief explanation.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
				
			||||||
 | 
					openwifi.service.key.password = mypassword
 | 
				
			||||||
 | 
					openwifi.system.data = $OWSEC_ROOT/data
 | 
				
			||||||
 | 
					openwifi.system.uri.private = https://localhost:17004
 | 
				
			||||||
 | 
					openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16002
 | 
				
			||||||
 | 
					openwifi.system.uri.ui = https://ucentral-ui.arilia.com
 | 
				
			||||||
 | 
					openwifi.security.restapi.disable = false
 | 
				
			||||||
 | 
					openwifi.system.commandchannel = /tmp/app.ucentralfms
 | 
				
			||||||
 | 
					openwifi.autoprovisioning = true
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					#### openwifi.service.key
 | 
				
			||||||
 | 
					From time to time, the microservice must encrypt information. This is the key it should use. You may use the
 | 
				
			||||||
 | 
					same keey as you RESTAPI or your server.
 | 
				
			||||||
 | 
					#### openwifi.service.key.password
 | 
				
			||||||
 | 
					The password for the `openwifi.service.key`
 | 
				
			||||||
 | 
					#### openwifi.system.data
 | 
				
			||||||
 | 
					The location of system data. This path must exist.
 | 
				
			||||||
 | 
					#### openwifi.system.uri.private
 | 
				
			||||||
 | 
					The URI to reach the controller on the internal port.
 | 
				
			||||||
 | 
					#### openwifi.system.uri.public
 | 
				
			||||||
 | 
					The URI to reach the controller from the outside world.
 | 
				
			||||||
 | 
					#### openwifi.system.uri.ui
 | 
				
			||||||
 | 
					The URI of the UI to manage this service
 | 
				
			||||||
 | 
					#### openwifi.security.restapi.disable
 | 
				
			||||||
 | 
					This allows to disable security for internal and external API calls. This should only be used if the controller
 | 
				
			||||||
 | 
					sits behind an application load balancer that will actually do TLS. Setting this to `true` disables security.
 | 
				
			||||||
 | 
					#### openwifi.system.commandchannel
 | 
				
			||||||
 | 
					The UNIX socket command channel used by this service.
 | 
				
			||||||
 | 
					#### openwifi.autoprovisioning
 | 
				
			||||||
 | 
					Allow unknown devices to be provisioned by the system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### ALB Support
 | 
				
			||||||
 | 
					In order to support an application load balancer health check verification, your need to provide the following parameters.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					alb.enable = true
 | 
				
			||||||
 | 
					alb.port = 16101
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Kafka
 | 
				
			||||||
 | 
					The controller use Kafka, like all the other microservices. You must configure the kafka section in order for the
 | 
				
			||||||
 | 
					system to work.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					openwifi.kafka.group.id = security
 | 
				
			||||||
 | 
					openwifi.kafka.client.id = security1
 | 
				
			||||||
 | 
					openwifi.kafka.enable = true
 | 
				
			||||||
 | 
					openwifi.kafka.brokerlist = my_Kafka.example.com:9092
 | 
				
			||||||
 | 
					openwifi.kafka.auto.commit = false
 | 
				
			||||||
 | 
					openwifi.kafka.queue.buffering.max.ms = 50
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### openwifi.kafka.group.id
 | 
				
			||||||
 | 
					The group ID is a single word that should identify the type of service tuning. In the case `security`
 | 
				
			||||||
 | 
					### openwifi.kafka.client.id
 | 
				
			||||||
 | 
					The client ID is a single service within that group ID. Each participant must have a unique client ID.
 | 
				
			||||||
 | 
					### openwifi.kafka.enable
 | 
				
			||||||
 | 
					Kafka should always be enabled.
 | 
				
			||||||
 | 
					### openwifi.kafka.brokerlist
 | 
				
			||||||
 | 
					The list of servers where your Kafka server is running. Comma separated.
 | 
				
			||||||
 | 
					### openwifi.kafka.auto.commit
 | 
				
			||||||
 | 
					Auto commit flag in Kafka. Leave as `false`.
 | 
				
			||||||
 | 
					### openwifi.kafka.queue.buffering.max.ms
 | 
				
			||||||
 | 
					Kafka buffering. Leave as `50`.
 | 
				
			||||||
 | 
					### Kafka security
 | 
				
			||||||
 | 
					If you intend to use SSL, you should look into Kafka Connect and specify the certificates below.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					penwifi.kafka.ssl.ca.location =
 | 
				
			||||||
 | 
					openwifi.kafka.ssl.certificate.location =
 | 
				
			||||||
 | 
					openwifi.kafka.ssl.key.location =
 | 
				
			||||||
 | 
					openwifi.kafka.ssl.key.password =
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### DB Type
 | 
				
			||||||
 | 
					The controller supports 3 types of Database. SQLite should only be used for sites with less than 100 APs or for testing in the lab.
 | 
				
			||||||
 | 
					In order to select which database to use, you must set the `storage.type` value to sqlite, postgresql, or mysql.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					storage.type = sqlite
 | 
				
			||||||
 | 
					#storage.type = postgresql
 | 
				
			||||||
 | 
					#storage.type = mysql
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Storage SQLite parameters
 | 
				
			||||||
 | 
					Additional parameters to set for SQLite. The only important one is `storage.type.sqlite.db` which is the database name on disk.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					storage.type.sqlite.db = security.db
 | 
				
			||||||
 | 
					storage.type.sqlite.idletime = 120
 | 
				
			||||||
 | 
					storage.type.sqlite.maxsessions = 128
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Storage Postgres
 | 
				
			||||||
 | 
					Additional parameters to set if you select Postgres for your database. You must specify `host`, `username`, `password`,
 | 
				
			||||||
 | 
					`database`, and `port`.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					storage.type.postgresql.maxsessions = 64
 | 
				
			||||||
 | 
					storage.type.postgresql.idletime = 60
 | 
				
			||||||
 | 
					storage.type.postgresql.host = localhost
 | 
				
			||||||
 | 
					storage.type.postgresql.username = security
 | 
				
			||||||
 | 
					storage.type.postgresql.password = security
 | 
				
			||||||
 | 
					storage.type.postgresql.database = security
 | 
				
			||||||
 | 
					storage.type.postgresql.port = 5432
 | 
				
			||||||
 | 
					storage.type.postgresql.connectiontimeout = 60
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Storage MySQL/MariaDB
 | 
				
			||||||
 | 
					Additional parameters to set if you select mysql for your database. You must specify `host`, `username`, `password`,
 | 
				
			||||||
 | 
					`database`, and `port`.
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					storage.type.mysql.maxsessions = 64
 | 
				
			||||||
 | 
					storage.type.mysql.idletime = 60
 | 
				
			||||||
 | 
					storage.type.mysql.host = localhost
 | 
				
			||||||
 | 
					storage.type.postgresql.username = security
 | 
				
			||||||
 | 
					storage.type.postgresql.password = security
 | 
				
			||||||
 | 
					storage.type.postgresql.database = security
 | 
				
			||||||
 | 
					storage.type.mysql.port = 3306
 | 
				
			||||||
 | 
					storage.type.mysql.connectiontimeout = 60
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Logging Parameters
 | 
				
			||||||
 | 
					The microservice provides extensive logging. If you would like to keep logging on disk, set the `logging.type = file`. If you only want
 | 
				
			||||||
 | 
					console logging, `set logging.type = console`. When selecting file, `logging.path` must exist. `logging.level` sets the
 | 
				
			||||||
 | 
					basic logging level for the entire controller. `logging.websocket` disables WebSocket logging.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```properties
 | 
				
			||||||
 | 
					logging.type = file
 | 
				
			||||||
 | 
					logging.path = $OWSEC_ROOT/logs
 | 
				
			||||||
 | 
					logging.level = information
 | 
				
			||||||
 | 
					logging.asynch = true
 | 
				
			||||||
 | 
					logging.websocket = false
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										38
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					# How to Contribute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We'd love to accept your patches and contributions to this project. There are
 | 
				
			||||||
 | 
					just a few small guidelines you need to follow.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Version of C++
 | 
				
			||||||
 | 
					This project is based on the C++17 standard and compiles as-is on most platforms 
 | 
				
			||||||
 | 
					using either clang or g++. Do not use C++21 or C++23 features for now. Some core 
 | 
				
			||||||
 | 
					libraries used in this project do not support C++21 or C++23 yet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Variable Naming
 | 
				
			||||||
 | 
					Naming of pretty much anything uses Pascal naming. Longer explicit names using casing. 
 | 
				
			||||||
 | 
					Member variable naming adds a `_` at the end of the vars. Try to
 | 
				
			||||||
 | 
					keep this standard going. Sometimes you must override a base class function and then of course
 | 
				
			||||||
 | 
					you need to follow the base class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## This is a cmake project
 | 
				
			||||||
 | 
					This is a cmake project, and you need to adhere to the cmake rules. If you need
 | 
				
			||||||
 | 
					to add a package to the CMakeList, you need to ensure that the package is available
 | 
				
			||||||
 | 
					on all required platforms and compiles. Remember that this project runs on Linux, OS X, 
 | 
				
			||||||
 | 
					and the Raspberry PI.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Licensed packages
 | 
				
			||||||
 | 
					When adding a package, you must also state the licensing for the package. MIT, BSD, Apache licenses
 | 
				
			||||||
 | 
					are acceptable. No commercial licenses are allowed. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## clang formatting
 | 
				
			||||||
 | 
					Please format your code using the included `.clang-format` file included in the project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					clang-format -i --style=<project root>/.clang-format myfile.cpp
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Pull Requests
 | 
				
			||||||
 | 
					All submissions, including submissions by project members, require review. We
 | 
				
			||||||
 | 
					accept GitHub pull requests. Please create a branch with the Jira name for addressing the issue you are fixing or the 
 | 
				
			||||||
 | 
					feature you are implementing.
 | 
				
			||||||
 | 
					Create a pull-request from the branch into master. 
 | 
				
			||||||
							
								
								
									
										92
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						@@ -1,24 +1,22 @@
 | 
				
			|||||||
ARG DEBIAN_VERSION=11.4-slim
 | 
					ARG DEBIAN_VERSION=11.5-slim
 | 
				
			||||||
ARG POCO_VERSION=poco-tip-v1
 | 
					ARG POCO_VERSION=poco-tip-v2
 | 
				
			||||||
ARG FMTLIB_VERSION=9.0.0
 | 
					 | 
				
			||||||
ARG CPPKAFKA_VERSION=tip-v1
 | 
					ARG CPPKAFKA_VERSION=tip-v1
 | 
				
			||||||
ARG JSON_VALIDATOR_VERSION=2.1.0
 | 
					ARG VALIJASON_VERSION=tip-v1
 | 
				
			||||||
ARG AWS_SDK_VERSION=1.9.315
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM debian:$DEBIAN_VERSION AS build-base
 | 
					FROM debian:$DEBIAN_VERSION AS build-base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
					RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
				
			||||||
    make cmake g++ git \
 | 
					    make cmake g++ git curl zip unzip pkg-config \
 | 
				
			||||||
    libpq-dev libmariadb-dev libmariadbclient-dev-compat \
 | 
					    libpq-dev libmariadb-dev libmariadbclient-dev-compat \
 | 
				
			||||||
    librdkafka-dev libboost-all-dev libssl-dev \
 | 
					    librdkafka-dev libboost-all-dev libssl-dev \
 | 
				
			||||||
    zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev
 | 
					    zlib1g-dev ca-certificates libcurl4-openssl-dev libfmt-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM build-base AS poco-build
 | 
					FROM build-base AS poco-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARG POCO_VERSION
 | 
					ARG POCO_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
 | 
					ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-poco/git/refs/tags/${POCO_VERSION} version.json
 | 
				
			||||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
 | 
					RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch ${POCO_VERSION} /poco
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /poco
 | 
					WORKDIR /poco
 | 
				
			||||||
RUN mkdir cmake-build
 | 
					RUN mkdir cmake-build
 | 
				
			||||||
@@ -27,26 +25,12 @@ RUN cmake ..
 | 
				
			|||||||
RUN cmake --build . --config Release -j8
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
RUN cmake --build . --target install
 | 
					RUN cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM build-base AS fmtlib-build
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ARG FMTLIB_VERSION
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
 | 
					 | 
				
			||||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
WORKDIR /fmtlib
 | 
					 | 
				
			||||||
RUN mkdir cmake-build
 | 
					 | 
				
			||||||
WORKDIR cmake-build
 | 
					 | 
				
			||||||
RUN cmake ..
 | 
					 | 
				
			||||||
RUN make
 | 
					 | 
				
			||||||
RUN make install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FROM build-base AS cppkafka-build
 | 
					FROM build-base AS cppkafka-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARG CPPKAFKA_VERSION
 | 
					ARG CPPKAFKA_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
 | 
					ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
 | 
				
			||||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
 | 
					RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /cppkafka
 | 
					WORKDIR /cppkafka
 | 
				
			||||||
RUN mkdir cmake-build
 | 
					RUN mkdir cmake-build
 | 
				
			||||||
@@ -55,63 +39,44 @@ RUN cmake ..
 | 
				
			|||||||
RUN cmake --build . --config Release -j8
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
RUN cmake --build . --target install
 | 
					RUN cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM build-base AS json-schema-validator-build
 | 
					FROM build-base AS valijson-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARG JSON_VALIDATOR_VERSION
 | 
					ARG VALIJASON_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
 | 
					ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-valijson/git/refs/tags/${VALIJASON_VERSION} version.json
 | 
				
			||||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
 | 
					RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch ${VALIJASON_VERSION} /valijson
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /json-schema-validator
 | 
					WORKDIR /valijson
 | 
				
			||||||
RUN mkdir cmake-build
 | 
					RUN mkdir cmake-build
 | 
				
			||||||
WORKDIR cmake-build
 | 
					WORKDIR cmake-build
 | 
				
			||||||
RUN cmake ..
 | 
					RUN cmake ..
 | 
				
			||||||
RUN make
 | 
					 | 
				
			||||||
RUN make install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FROM build-base AS aws-sdk-cpp-build
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ARG AWS_SDK_VERSION
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/tags/${AWS_SDK_VERSION} version.json
 | 
					 | 
				
			||||||
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp --branch ${AWS_SDK_VERSION} /aws-sdk-cpp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
WORKDIR /aws-sdk-cpp
 | 
					 | 
				
			||||||
RUN mkdir cmake-build
 | 
					 | 
				
			||||||
WORKDIR cmake-build
 | 
					 | 
				
			||||||
RUN cmake .. -DBUILD_ONLY="sns;s3" \
 | 
					 | 
				
			||||||
             -DCMAKE_BUILD_TYPE=Release \
 | 
					 | 
				
			||||||
             -DUSE_OPENSSL=ON \
 | 
					 | 
				
			||||||
             -DCPP_STANDARD=17 \
 | 
					 | 
				
			||||||
             -DBUILD_SHARED_LIBS=ON \
 | 
					 | 
				
			||||||
             -DCMAKE_CXX_FLAGS="-Wno-error=stringop-overflow -Wno-error=uninitialized" \
 | 
					 | 
				
			||||||
             -DAUTORUN_UNIT_TESTS=OFF
 | 
					 | 
				
			||||||
RUN cmake --build . --config Release -j8
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
RUN cmake --build . --target install
 | 
					RUN cmake --build . --target install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM build-base AS owsec-build
 | 
					FROM build-base AS owsec-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADD CMakeLists.txt build /owsec/
 | 
					ADD CMakeLists.txt build /owsec/
 | 
				
			||||||
 | 
					ADD overlays /owsec/overlays
 | 
				
			||||||
ADD cmake /owsec/cmake
 | 
					ADD cmake /owsec/cmake
 | 
				
			||||||
ADD src /owsec/src
 | 
					ADD src /owsec/src
 | 
				
			||||||
ADD .git /owsec/.git
 | 
					ADD .git /owsec/.git
 | 
				
			||||||
 | 
					ARG VCPKG_VERSION=2022.11.14
 | 
				
			||||||
 | 
					RUN git clone --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg && \
 | 
				
			||||||
 | 
					    ./vcpkg/bootstrap-vcpkg.sh && \
 | 
				
			||||||
 | 
					    mkdir /vcpkg/custom-triplets && \
 | 
				
			||||||
 | 
					    cp /vcpkg/triplets/x64-linux.cmake /vcpkg/custom-triplets/x64-linux.cmake && \
 | 
				
			||||||
 | 
					    sed -i 's/set(VCPKG_LIBRARY.*/set(VCPKG_LIBRARY_LINKAGE dynamic)/g' /vcpkg/custom-triplets/x64-linux.cmake && \
 | 
				
			||||||
 | 
					    ./vcpkg/vcpkg install aws-sdk-cpp[sns]:x64-linux json-schema-validator:x64-linux --overlay-triplets=/vcpkg/custom-triplets --overlay-ports=/owsec/overlays
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY --from=poco-build /usr/local/include /usr/local/include
 | 
					COPY --from=poco-build /usr/local/include /usr/local/include
 | 
				
			||||||
COPY --from=poco-build /usr/local/lib /usr/local/lib
 | 
					COPY --from=poco-build /usr/local/lib /usr/local/lib
 | 
				
			||||||
COPY --from=cppkafka-build /usr/local/include /usr/local/include
 | 
					COPY --from=cppkafka-build /usr/local/include /usr/local/include
 | 
				
			||||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
 | 
					COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
 | 
				
			||||||
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
 | 
					 | 
				
			||||||
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
 | 
					 | 
				
			||||||
COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include
 | 
					 | 
				
			||||||
COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
COPY --from=fmtlib-build /usr/local/include /usr/local/include
 | 
					 | 
				
			||||||
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /owsec
 | 
					WORKDIR /owsec
 | 
				
			||||||
RUN mkdir cmake-build
 | 
					RUN mkdir cmake-build
 | 
				
			||||||
WORKDIR /owsec/cmake-build
 | 
					WORKDIR /owsec/cmake-build
 | 
				
			||||||
RUN cmake ..
 | 
					RUN cmake -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake ..
 | 
				
			||||||
RUN cmake --build . --config Release -j8
 | 
					RUN cmake --build . --config Release -j8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM debian:$DEBIAN_VERSION
 | 
					FROM debian:$DEBIAN_VERSION
 | 
				
			||||||
@@ -128,7 +93,7 @@ RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
					RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
				
			||||||
    librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
 | 
					    librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
 | 
				
			||||||
    libmariadb-dev-compat libpq5 unixodbc postgresql-client
 | 
					    libmariadb-dev-compat libpq5 postgresql-client libfmt7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY readiness_check /readiness_check
 | 
					COPY readiness_check /readiness_check
 | 
				
			||||||
COPY test_scripts/curl/cli /cli
 | 
					COPY test_scripts/curl/cli /cli
 | 
				
			||||||
@@ -142,11 +107,10 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr
 | 
				
			|||||||
    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
 | 
					    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec
 | 
					COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec
 | 
				
			||||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib
 | 
					COPY --from=owsec-build /vcpkg/installed/x64-linux/lib/ /usr/local/lib/
 | 
				
			||||||
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib
 | 
					COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/ /usr/local/lib/
 | 
				
			||||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib
 | 
					COPY --from=poco-build /poco/cmake-build/lib/ /usr/local/lib/
 | 
				
			||||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib
 | 
					COPY --from=valijson-build /usr/local/include /usr/local/include
 | 
				
			||||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN ldconfig
 | 
					RUN ldconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										310
									
								
								README.md
									
									
									
									
									
								
							
							
						
						@@ -1,66 +1,100 @@
 | 
				
			|||||||
# ucentralsec
 | 
					<p align="center">
 | 
				
			||||||
 | 
					    <img src="images/project/logo.svg" width="200"/>
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uCentralSec is the Authentication & Resource Policy Access service for the uCentral system. In order to use the uCentral system
 | 
					# OpenWiFi Security  (OWSEC)
 | 
				
			||||||
you must have at least 1 uCentralSec. uCentralSec is the first point of contact for the entire architecture. We strongly recommend using Docker 
 | 
					
 | 
				
			||||||
to deploy all the uCentral services. If you would like to develop and play with the source, please do.
 | 
					## What is it?
 | 
				
			||||||
 | 
					The OWSEC is a service for the TIP OpenWiFi CloudSDK (OWSDK).
 | 
				
			||||||
 | 
					OWSEC is the Authentication and Resource Policy Access service for the TIP
 | 
				
			||||||
 | 
					OpenWiFi Cloud SDK (OWSDK). OWSEC,
 | 
				
			||||||
 | 
					like all other OWSDK microservices, is defined using an OpenAPI definition and uses the ucentral communication
 | 
				
			||||||
 | 
					protocol to interact with Access Points. To use the OWSUB, you either need to [build it](#building) or use the
 | 
				
			||||||
 | 
					[Docker version](#docker).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Building
 | 
				
			||||||
 | 
					To build the microservice from source, please follow the instructions in [here](./BUILDING.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Docker
 | 
				
			||||||
 | 
					To use the CLoudSDK deployment please follow [here](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## OpenAPI
 | 
					## OpenAPI
 | 
				
			||||||
Like all other uCentral services, uCentralSec is defined through an OpenAPI. You can use this API to build your own applications or integration modules
 | 
					You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralsec/).
 | 
				
			||||||
into your own systems. If all you need it to access the uCentralGW for example (the service that manages the APs), you will need to:
 | 
					Also, you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openapi/owsec.yaml)) to get interactive docs page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage
 | 
				
			||||||
 | 
					Like all other OWSDK services, OWSEC is defined through an OpenAPI. You can use this API to build your own 
 | 
				
			||||||
 | 
					applications or integration modules into your own systems. If all you need it to access the OWGW for 
 | 
				
			||||||
 | 
					example (the service that manages the APs), you will need to:
 | 
				
			||||||
- get a token (`/oauth2`)
 | 
					- get a token (`/oauth2`)
 | 
				
			||||||
- find the endpoints on the system (`/systemEndpoints`) 
 | 
					- find the endpoints on the system (`/systemEndpoints`) 
 | 
				
			||||||
- choose one to manage (pick an endpoint that matches what you are trying to do by looking at its `type`. For the gateway, type = ucentrtalgw)
 | 
					- choose a microservice to manage (pick an endpoint that matches what you are trying to do by looking at its 
 | 
				
			||||||
- make your calls (use the PublicEndPoint of the corresponding entry to make your calls, do not forget to add `/api/v1` as the root os the call)
 | 
					`type`. For the Cloud SDK Controller, type = owgw)
 | 
				
			||||||
 | 
					- make your calls (use the PublicEndPoint of the corresponding entry to make your calls, 
 | 
				
			||||||
 | 
					do not forget to add `/api/v1` as the root os the call)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The CLI for the [uCentralGW](https://github.com/telecominfraproject/wlan-cloud-ucentralgw/blob/main/test_scripts/curl/cli) has a very good example of this. 
 | 
					The CLI for the [OWGW](https://github.com/telecominfraproject/wlan-cloud-ucentralsec/blob/main/test_scripts/curl/cli) has 
 | 
				
			||||||
Look for the `setgateway` function.
 | 
					a very good example of this. Look for the `setgateway` function.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralsec/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also, you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://validator.swagger.io/validator?url=https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openpapi/owsec.yaml)) to get interactive docs page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Expected directory layout
 | 
				
			||||||
 | 
					From the directory where your cloned source is, you will need to create the `certs`, `logs`, and `uploads` directories.
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					mkdir certs
 | 
				
			||||||
 | 
					mkdir certs/cas
 | 
				
			||||||
 | 
					mkdir logs
 | 
				
			||||||
 | 
					mkdir uploads
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					You should now have the following:
 | 
				
			||||||
 | 
					```text
 | 
				
			||||||
 | 
					--+-- certs
 | 
				
			||||||
 | 
					  |   +--- cas
 | 
				
			||||||
 | 
					  +-- cmake
 | 
				
			||||||
 | 
					  +-- cmake-build
 | 
				
			||||||
 | 
					  +-- logs
 | 
				
			||||||
 | 
					  +-- src
 | 
				
			||||||
 | 
					  +-- test_scripts
 | 
				
			||||||
 | 
					  +-- openapi
 | 
				
			||||||
 | 
					  +-- uploads
 | 
				
			||||||
 | 
					  +-- owsec.properties
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Certificate
 | 
				
			||||||
 | 
					The OWSEC uses a certificate to provide security for the REST API Certificate to secure the Northbound API.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### The `certs` directory
 | 
				
			||||||
 | 
					For all deployments, you will need the following `certs` directory, populated with the proper files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```text
 | 
				
			||||||
 | 
					certs ---+--- restapi-ca.pem
 | 
				
			||||||
 | 
					         +--- restapi-cert.pem
 | 
				
			||||||
 | 
					         +--- restapi-key.pem
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Firewall Considerations
 | 
					## Firewall Considerations
 | 
				
			||||||
The entire uCentral systems uses several MicroServices. In order for the whole system to work, you should provide the following port
 | 
					| Port  | Description                                | Configurable |
 | 
				
			||||||
access:
 | 
					|:------|:-------------------------------------------|:------------:|
 | 
				
			||||||
 | 
					| 16001 | Default port from the devices to the OWSEC |     yes      |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Security
 | 
					### Environment variables
 | 
				
			||||||
  - Properties file: owsec.properties
 | 
					The following environment variables should be set from the root directory of the service. They tell the OWGW process where to find
 | 
				
			||||||
  - Ports
 | 
					the configuration and the root directory.
 | 
				
			||||||
    - Public: 16001
 | 
					```bash
 | 
				
			||||||
    - Private: 17001
 | 
					export OWGW_ROOT=`pwd`
 | 
				
			||||||
    - ALB: 16101
 | 
					export OWGW_CONFIG=`pwd`
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					You can run the shell script `set_env.sh` from the microservice root.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Gateway:
 | 
					### OWSEC Service Configuration
 | 
				
			||||||
  - Properties file: owgw.properties
 | 
					The configuration is kept in a file called `owsec.properties`. To understand the content of this file,
 | 
				
			||||||
  - Ports
 | 
					please look [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/CONFIGURATION.md)
 | 
				
			||||||
    - Public: 16002
 | 
					 | 
				
			||||||
    - Private: 17002
 | 
					 | 
				
			||||||
    - ALB: 16102
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Firmware:
 | 
					 | 
				
			||||||
  - Properties file: owfms.properties
 | 
					 | 
				
			||||||
  - Ports
 | 
					 | 
				
			||||||
    - Public: 16004
 | 
					 | 
				
			||||||
    - Private: 17004
 | 
					 | 
				
			||||||
    - ALB: 16104
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Provisioning:
 | 
					 | 
				
			||||||
  - Properties file: owprov.properties
 | 
					 | 
				
			||||||
  - Ports
 | 
					 | 
				
			||||||
    - Public: 16004
 | 
					 | 
				
			||||||
    - Private: 17004
 | 
					 | 
				
			||||||
    - ALB: 16104
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Security Configuration
 | 
					 | 
				
			||||||
The service relies on a properties configuration file called `owsec.properties`. In this file, you should configure several entries. Many values are optional 
 | 
					 | 
				
			||||||
and you can rely on the defaults. Here are some values of note:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### `authentication.default.password`
 | 
					 | 
				
			||||||
Set the hash of the default username and password. Please look below on how to do this. 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### `authentication.default.username`
 | 
					 | 
				
			||||||
Set the default username to use to login.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Default username and password
 | 
					### Default username and password
 | 
				
			||||||
The default username and password are set in `owsec.properties` file. The following entries manage the username and password
 | 
					The default username and password are set in `owsec.properties` file. The following entries manage the username and password
 | 
				
			||||||
```text
 | 
					```properties
 | 
				
			||||||
authentication.default.username = tip@ucentral.com
 | 
					authentication.default.username = tip@ucentral.com
 | 
				
			||||||
authentication.default.password = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 | 
					authentication.default.password = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
@@ -75,36 +109,17 @@ echo -n "weLoveWifiroot@system.com" | shasum -a 256
 | 
				
			|||||||
b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c  -
 | 
					b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c  -
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
Then you need to modify your properties file like this
 | 
					Then you need to modify your properties file like this
 | 
				
			||||||
```text
 | 
					```properties
 | 
				
			||||||
authentication.default.username = root@system.com
 | 
					authentication.default.username = root@system.com
 | 
				
			||||||
authentication.default.password = b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c
 | 
					authentication.default.password = b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
Remember, when you login, use `root@system.com` with the password `weLoveWifi`, not this monster digit sequence.
 | 
					Remember, when you login, use `root@system.com` with the password `weLoveWifi`, not this monster digit sequence.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Is this safe?
 | 
					 | 
				
			||||||
Is this safe to show the hash in a text file? Let me put it this way, if you can find a way to break this encryption, you
 | 
					 | 
				
			||||||
would have control over the entire internet. It's incredibly safe. If you love math, you can find a lot of videos explaining
 | 
					 | 
				
			||||||
how hashes work and why they are safe.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### `authentication.validation.expression`
 | 
					 | 
				
			||||||
This is a regular expression (regex) to verify the incoming password. You can find many examples on the internet on how to create these expressions. I suggest 
 | 
					 | 
				
			||||||
that using Google is your friend. Someone has figured out what you want to do already. Click [here](https://stackoverflow.com/questions/19605150/regex-for-password-must-contain-at-least-eight-characters-at-least-one-number-a)
 | 
					 | 
				
			||||||
to get a sample. The default is
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### `authentication.oldpasswords`
 | 
					 | 
				
			||||||
The number of older passwords to keep. Default is 5.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Changing default password
 | 
					### Changing default password
 | 
				
			||||||
 | 
					 | 
				
			||||||
On the first startup of the service new user will be created with the default credentials from properties `authentication.default.username` and `authentication.default.password`, but **you will have to change the password** before making any real requests.
 | 
					On the first startup of the service new user will be created with the default credentials from properties `authentication.default.username` and `authentication.default.password`, but **you will have to change the password** before making any real requests.
 | 
				
			||||||
 | 
					 | 
				
			||||||
You can this using [owgw-ui](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui/) on first login or using the following script:
 | 
					You can this using [owgw-ui](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui/) on first login or using the following script:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```bash
 | 
				
			||||||
export OWSEC=openwifi.wlan.local:16001 # endpoint to your owsec RESTAPI endpoint
 | 
					export OWSEC=openwifi.wlan.local:16001 # endpoint to your owsec RESTAPI endpoint
 | 
				
			||||||
#export FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates)
 | 
					#export FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates)
 | 
				
			||||||
export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username'
 | 
					export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username'
 | 
				
			||||||
@@ -115,7 +130,7 @@ test_scripts/curl/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CLI is also included in Docker image if you want to run it this way:
 | 
					CLI is also included in Docker image if you want to run it this way:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```bash
 | 
				
			||||||
export OWSEC=openwifi.wlan.local:16001
 | 
					export OWSEC=openwifi.wlan.local:16001
 | 
				
			||||||
#export FLAGS="-k"
 | 
					#export FLAGS="-k"
 | 
				
			||||||
export OWSEC_DEFAULT_USERNAME=root@system.com
 | 
					export OWSEC_DEFAULT_USERNAME=root@system.com
 | 
				
			||||||
@@ -132,136 +147,25 @@ docker run --rm -ti \
 | 
				
			|||||||
  /cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
 | 
					  /cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Kafka integration
 | 
					 | 
				
			||||||
This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running
 | 
					 | 
				
			||||||
in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
openwifi.kafka.group.id = security
 | 
					 | 
				
			||||||
openwifi.kafka.client.id = security1
 | 
					 | 
				
			||||||
openwifi.kafka.enable = true
 | 
					 | 
				
			||||||
openwifi.kafka.brokerlist = my.kafkaserver.arilia.com:9092
 | 
					 | 
				
			||||||
openwifi.kafka.auto.commit = false
 | 
					 | 
				
			||||||
openwifi.kafka.queue.buffering.max.ms = 50
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `openwifi.kafka.brokerlist`
 | 
					 | 
				
			||||||
This is the list of your kafka brokers. This is a comma separated list. You should use IP addresses or FQDNs and the relevant ports, usually 9092 is the 
 | 
					 | 
				
			||||||
default.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `openwifi.kafka.group.id`
 | 
					 | 
				
			||||||
Every service on the Kafka bux must have a unique value (at least in our case). This should be a string. We suggest using a name corresponding to the 
 | 
					 | 
				
			||||||
function provided. In this case, security.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Certificates
 | 
					 | 
				
			||||||
Of course we need certificates. In our case, we already have existing certificates we have. You should find out how your file name correspond
 | 
					 | 
				
			||||||
to our names. We suggest reusing the same names we use so it is easier to use our default configuration files. We suggest using proper certificates 
 | 
					 | 
				
			||||||
for the publicly visible interfaces. For private interfaces, self-signed certificates are OK. We will not describe how to use/create private certificates 
 | 
					 | 
				
			||||||
here.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### The public interface
 | 
					 | 
				
			||||||
Here are the parameters for the public interface. The important files are:
 | 
					 | 
				
			||||||
- `restapi-ca.pem` : the CA of your certificate
 | 
					 | 
				
			||||||
- `restapi-cert.pem` : the certificate for the public interface
 | 
					 | 
				
			||||||
- `restapi-key.pem` : the key associated with this certificate
 | 
					 | 
				
			||||||
- `openwifi.restapi.host.0.key.password` : if you key is password protected, you may supply that password here.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.backlog = 100
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.security = relaxed
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.address = *
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.port = 16001
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
					 | 
				
			||||||
openwifi.restapi.host.0.key.password = mypassword
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### The private interface
 | 
					 | 
				
			||||||
The private interface is used for service-to-service communication. You can use self-signed certificates here or letsencrypt. The file names are similar 
 | 
					 | 
				
			||||||
to the filenames used in the previous section.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
openwifi.internal.restapi.host.0.backlog = 100
 | 
					 | 
				
			||||||
openwifi.internal.restapi.host.0.security = relaxed
 | 
					 | 
				
			||||||
openwifi.internal.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
 | 
					 | 
				
			||||||
openwifi.internal.restapi.host.0.address = *
 | 
					 | 
				
			||||||
openwifi.internal.restapi.host.0.port = 17001
 | 
					 | 
				
			||||||
openwifi.internal.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
 | 
					 | 
				
			||||||
openwifi.internal.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
					 | 
				
			||||||
openwifi.internal.restapi.host.0.key.password = mypassword
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Other important values
 | 
					 | 
				
			||||||
Here are other important values you must set.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
openwifi.system.data = $OWSEC_ROOT/data
 | 
					 | 
				
			||||||
openwifi.system.uri.private = https://localhost:17001
 | 
					 | 
				
			||||||
openwifi.system.uri.public = https://openwifi.dpaas.arilia.com:16001
 | 
					 | 
				
			||||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
 | 
					 | 
				
			||||||
openwifi.system.commandchannel = /tmp/app.ucentralsec
 | 
					 | 
				
			||||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
					 | 
				
			||||||
openwifi.service.key.password = mypassword
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
#### `openwifi.system.data`
 | 
					 | 
				
			||||||
The location of some important data files including the user name database.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `openwifi.system.uri.private`
 | 
					 | 
				
			||||||
This is the FQDN used internally between services.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### `openwifi.system.uri.public`
 | 
					 | 
				
			||||||
This is the FQDN used externally serving the OpenAPI interface.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Sending SMS for Multifactor Aithentication
 | 
					 | 
				
			||||||
`owsec` hs the ability to send SMS messages to users during login or to send notifications. In order to do so,
 | 
					 | 
				
			||||||
an SMS provider must be configured. At present time, 2 providers are supported: Tilio and AWS SNS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### AWS SMS
 | 
					 | 
				
			||||||
For SNS you must create an IAM ID that has sns:sendmessage rights.  
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
smssender.enabled = true
 | 
					 | 
				
			||||||
smssender.provider = aws
 | 
					 | 
				
			||||||
smssender.aws.secretkey = ***************************************
 | 
					 | 
				
			||||||
smssender.aws.accesskey = ***************************************
 | 
					 | 
				
			||||||
smssender.aws.region = **************
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Twilio
 | 
					 | 
				
			||||||
For Twilio, you must provide the following
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
smssender.enabled = true
 | 
					 | 
				
			||||||
smssender.provider = twilio
 | 
					 | 
				
			||||||
smssender.twilio.sid = ***********************
 | 
					 | 
				
			||||||
smssender.twilio.token = **********************
 | 
					 | 
				
			||||||
smssender.twilio.phonenumber = +18888888888
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### `owsec` Messaging Configuration
 | 
					 | 
				
			||||||
`owsec` nay require to send e-mails. In order to do so, you must configure an email sender. We have run tests 
 | 
					 | 
				
			||||||
with GMail and AWS SES. For each, you must obtain the proper credentials and insert them in this configuration as well
 | 
					 | 
				
			||||||
as the proper mail host.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
mailer.enabled = true
 | 
					 | 
				
			||||||
mailer.hostname = smtp.gmail.com
 | 
					 | 
				
			||||||
mailer.username = ************************
 | 
					 | 
				
			||||||
mailer.password = ************************
 | 
					 | 
				
			||||||
mailer.sender = OpenWIFI
 | 
					 | 
				
			||||||
mailer.loginmethod = login
 | 
					 | 
				
			||||||
mailer.port = 587
 | 
					 | 
				
			||||||
mailer.templates = $OWSEC_ROOT/templates
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#### Google Authenticator
 | 
					 | 
				
			||||||
In order to use the Google Time-based One-Time Password (TOTP), the user must download the Google Authenticator 
 | 
					 | 
				
			||||||
on any other app that support the TOTP protocol. You should include the following in your configuration
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
totp.issuer = OrgName
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
It is very important that you not use spaces in your OrgName.
 | 
					It is very important that you not use spaces in your OrgName.
 | 
				
			||||||
 | 
					## Kafka topics
 | 
				
			||||||
 | 
					Toe read more about Kafka, follow the [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/KAFKA.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Contributions
 | 
				
			||||||
 | 
					We need more contributors. Should you wish to contribute,
 | 
				
			||||||
 | 
					please follow the [contributions](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CONTRIBUTING.md) document.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Pull Requests
 | 
				
			||||||
 | 
					Please create a branch with the Jira addressing the issue you are fixing or the feature you are implementing.
 | 
				
			||||||
 | 
					Create a pull-request from the branch into master.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Additional OWSDK Microservices
 | 
				
			||||||
 | 
					Here is a list of additional OWSDK microservices
 | 
				
			||||||
 | 
					| Name | Description | Link | OpenAPI |
 | 
				
			||||||
 | 
					| :--- | :--- | :---: | :---: |
 | 
				
			||||||
 | 
					| OWSEC | Security Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml) |
 | 
				
			||||||
 | 
					| OWGW | Controller Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/openapi/owgw.yaml) |
 | 
				
			||||||
 | 
					| OWFMS | Firmware Management Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms/blob/main/openapi/owfms.yaml) |
 | 
				
			||||||
 | 
					| OWPROV | Provisioning Service | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov) | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openapi/owprov.yaml) |
 | 
				
			||||||
 | 
					| OWANALYTICS | Analytics Service | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics) | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics/blob/main/openapi/owanalytics.yaml) |
 | 
				
			||||||
 | 
					| OWSUB | Subscriber Service | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal) | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal/blob/main/openapi/userportal.yaml) |
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,16 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
 | 
				
			|||||||
  STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owsec"} \
 | 
					  STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owsec"} \
 | 
				
			||||||
  STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owsec"} \
 | 
					  STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owsec"} \
 | 
				
			||||||
  STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
 | 
					  STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
 | 
				
			||||||
 | 
					  USER_HELPER_EMAIL=${USER_HELPER_EMAIL:-"openwifi@telecominfraproject.com"} \
 | 
				
			||||||
 | 
					  SUB_HELPER_EMAIL=${SUB_HELPER_EMAIL:-"openwifi@telecominfraproject.com"} \
 | 
				
			||||||
 | 
					  GLOBAL_USER_HELPER_EMAIL=${GLOBAL_USER_HELPER_EMAIL:-"openwifi@telecominfraproject.com"} \
 | 
				
			||||||
 | 
					  GLOBAL_SUB_HELPER_EMAIL=${GLOBAL_SUB_HELPER_EMAIL:-"openwifi@telecominfraproject.com"} \
 | 
				
			||||||
 | 
					  USER_HELPER_SITE=${USER_HELPER_SITE:-"https://openwifi.telecominfraproject.com"} \
 | 
				
			||||||
 | 
					  SUB_HELPER_SITE=${SUB_HELPER_SITE:-"https://openwifi.telecominfraproject.com"} \
 | 
				
			||||||
 | 
					  USER_SYSTEM_LOGIN=${USER_SYSTEM_LOGIN:-"https://openwifi.telecominfraproject.com"} \
 | 
				
			||||||
 | 
					  SUB_SYSTEM_LOGIN=${SUB_SYSTEM_LOGIN:-"https://openwifi.telecominfraproject.com"} \
 | 
				
			||||||
 | 
					  USER_SIGNATURE=${USER_SIGNATURE:-"Telecom Infra Project"} \
 | 
				
			||||||
 | 
					  SUB_SIGNATURE=${SUB_SIGNATURE:-"Telecom Infra Project"} \
 | 
				
			||||||
  envsubst < /owsec.properties.tmpl > $OWSEC_CONFIG/owsec.properties
 | 
					  envsubst < /owsec.properties.tmpl > $OWSEC_CONFIG/owsec.properties
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
 | 
				
			|||||||
images:
 | 
					images:
 | 
				
			||||||
  owsec:
 | 
					  owsec:
 | 
				
			||||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
 | 
					    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
 | 
				
			||||||
    tag: main
 | 
					    tag: v3.2.0
 | 
				
			||||||
    pullPolicy: Always
 | 
					    pullPolicy: Always
 | 
				
			||||||
#    regcred:
 | 
					#    regcred:
 | 
				
			||||||
#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf160d.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 104 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf188.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 80 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf188n.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 80 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf194c.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 75 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf194c4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 75 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf808.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 218 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf809.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 158 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_eap101.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 140 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_eap102.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 121 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecs4100-12ph.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 44 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecw5211.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 192 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecw5410.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 197 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_oap100.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 50 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_spw2ac1200-lan-poe.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_spw2ac1200.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ssw2ac2600.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 51 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/hfcl_ion4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 72 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/hfcl_ion4.yml.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 72 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/indio_um-305ac.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 34 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_e8450-ubi.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 98 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea6350-v4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 89 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea6350.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 89 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea8300.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 204 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tp-link_ec420-g1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 159 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ec420.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 159 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex227.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 103 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex228.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 103 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex447.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 103 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr40x9.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr6018.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 80 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr6018_v4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 80 KiB  | 
| 
		 Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB  | 
							
								
								
									
										165
									
								
								images/project/logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
				
			||||||
 | 
					<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
				
			||||||
 | 
						 viewBox="0 0 141.5 185.6" style="enable-background:new 0 0 141.5 185.6;" xml:space="preserve">
 | 
				
			||||||
 | 
					<style type="text/css">
 | 
				
			||||||
 | 
						.st0{fill:#414141;}
 | 
				
			||||||
 | 
						.st1{fill:#FFFFFF;}
 | 
				
			||||||
 | 
						.st2{fill:#FED206;}
 | 
				
			||||||
 | 
						.st3{fill:#EB6F53;}
 | 
				
			||||||
 | 
						.st4{fill:#3BA9B6;}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
						<g>
 | 
				
			||||||
 | 
							<path class="st0" d="M120.7,183.9H21.5c-10.8,0-19.5-8.7-19.5-19.5V20.5c0-10.8,8.7-19.5,19.5-19.5h99.2
 | 
				
			||||||
 | 
								c10.8,0,19.5,8.7,19.5,19.5v143.9C140.2,175.2,131.5,183.9,120.7,183.9z"/>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M46.3,166.2v-3.4h-1.2v-0.6h3.1v0.6H47v3.4H46.3z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M49,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H49z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M52.6,166.2v-4h0.7v3.4h1.8v0.6H52.6z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M55.7,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H55.7z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M59.1,164.2c0-1.2,0.9-2.1,2.1-2.1c0.8,0,1.3,0.4,1.6,0.9l-0.6,0.3c-0.2-0.3-0.6-0.6-1-0.6
 | 
				
			||||||
 | 
											c-0.8,0-1.4,0.6-1.4,1.4c0,0.8,0.6,1.4,1.4,1.4c0.4,0,0.8-0.3,1-0.6l0.6,0.3c-0.3,0.5-0.8,0.9-1.6,0.9
 | 
				
			||||||
 | 
											C60,166.3,59.1,165.5,59.1,164.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M63.2,164.2c0-1.2,0.8-2.1,2-2.1c1.2,0,2,0.9,2,2.1c0,1.2-0.8,2.1-2,2.1C64,166.3,63.2,165.4,63.2,164.2z
 | 
				
			||||||
 | 
											 M66.5,164.2c0-0.8-0.5-1.4-1.3-1.4c-0.8,0-1.3,0.6-1.3,1.4c0,0.8,0.5,1.4,1.3,1.4C66,165.7,66.5,165,66.5,164.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M71.3,166.2v-3.1l-1.2,3.1h-0.3l-1.2-3.1v3.1h-0.7v-4h1l1.1,2.7l1.1-2.7h1v4H71.3z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M75.7,166.2v-4h0.7v4H75.7z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M80.4,166.2l-2.1-2.8v2.8h-0.7v-4h0.7l2,2.8v-2.8h0.7v4H80.4z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M82.3,166.2v-4H85v0.6h-2v1h2v0.6h-2v1.7H82.3z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M87.9,166.2l-0.9-1.5h-0.7v1.5h-0.7v-4h1.7c0.8,0,1.3,0.5,1.3,1.2c0,0.7-0.5,1.1-0.9,1.2l1,1.6H87.9z
 | 
				
			||||||
 | 
											 M88,163.5c0-0.4-0.3-0.6-0.7-0.6h-1v1.3h1C87.7,164.1,88,163.9,88,163.5z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M92.4,166.2l-0.3-0.8h-1.8l-0.3,0.8h-0.8l1.6-4h0.9l1.6,4H92.4z M91.2,162.9l-0.7,1.9h1.4L91.2,162.9z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M95.8,166.2v-4h1.5c0.8,0,1.2,0.5,1.2,1.2c0,0.6-0.4,1.2-1.2,1.2h-1.2v1.7H95.8z M98.2,163.4
 | 
				
			||||||
 | 
											c0-0.5-0.3-0.9-0.9-0.9h-1.1v1.7h1.1C97.8,164.3,98.2,163.9,98.2,163.4z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M101.5,166.2l-1.1-1.6h-0.9v1.6h-0.3v-4h1.5c0.7,0,1.2,0.4,1.2,1.2c0,0.7-0.5,1.1-1.1,1.1l1.2,1.7H101.5z
 | 
				
			||||||
 | 
											 M101.6,163.4c0-0.5-0.4-0.9-0.9-0.9h-1.1v1.7h1.1C101.2,164.3,101.6,163.9,101.6,163.4z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M102.8,164.2c0-1.2,0.8-2.1,1.9-2.1c1.2,0,1.9,0.9,1.9,2.1c0,1.2-0.8,2.1-1.9,2.1
 | 
				
			||||||
 | 
											C103.6,166.3,102.8,165.4,102.8,164.2z M106.3,164.2c0-1-0.6-1.7-1.6-1.7c-1,0-1.6,0.7-1.6,1.7c0,1,0.6,1.7,1.6,1.7
 | 
				
			||||||
 | 
											C105.7,166,106.3,165.2,106.3,164.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M106.9,165.8l0.2-0.3c0.2,0.2,0.4,0.4,0.8,0.4c0.5,0,0.9-0.4,0.9-0.9v-2.8h0.3v2.8c0,0.8-0.5,1.2-1.2,1.2
 | 
				
			||||||
 | 
											C107.5,166.3,107.2,166.1,106.9,165.8z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M110.4,166.2v-4h2.5v0.3h-2.2v1.5h2.1v0.3h-2.1v1.6h2.2v0.3H110.4z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M113.5,164.2c0-1.2,0.9-2.1,2-2.1c0.6,0,1.1,0.3,1.5,0.7l-0.3,0.2c-0.3-0.3-0.7-0.6-1.2-0.6
 | 
				
			||||||
 | 
											c-0.9,0-1.7,0.7-1.7,1.7c0,1,0.7,1.7,1.7,1.7c0.5,0,0.9-0.2,1.2-0.6l0.3,0.2c-0.4,0.4-0.8,0.7-1.5,0.7
 | 
				
			||||||
 | 
											C114.4,166.3,113.5,165.5,113.5,164.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st1" d="M118.7,166.2v-3.7h-1.3v-0.3h2.9v0.3H119v3.7H118.7z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<polygon class="st1" points="26.3,163.8 31.6,158.5 36.9,163.8 37.7,163.8 31.6,157.6 25.5,163.8 				"/>
 | 
				
			||||||
 | 
									<polygon class="st1" points="36.9,164.7 31.6,170 26.3,164.7 25.5,164.7 31.6,170.8 37.7,164.7 				"/>
 | 
				
			||||||
 | 
									<polygon class="st1" points="31,163.8 36.3,158.5 41.6,163.8 42.5,163.8 36.3,157.6 30.2,163.8 				"/>
 | 
				
			||||||
 | 
									<polygon class="st1" points="41.6,164.7 36.3,170 31,164.7 30.2,164.7 36.3,170.8 42.5,164.7 				"/>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<path class="st1" d="M33.2,100.7c-4.6,0-8.3,3.7-8.3,8.3s3.7,8.3,8.3,8.3s8.3-3.7,8.3-8.3S37.8,100.7,33.2,100.7z"/>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st2" d="M33.2,35.2c40.7,0,73.8,33.1,73.8,73.8c0,0.7,0,1.4,0,2.1c0,1.7,0.6,3.3,1.7,4.6c1.2,1.2,2.8,1.9,4.5,2
 | 
				
			||||||
 | 
											l0.2,0c3.5,0,6.3-2.7,6.4-6.2c0-0.8,0-1.7,0-2.5c0-47.7-38.8-86.6-86.6-86.6c-0.8,0-1.7,0-2.5,0c-1.7,0-3.3,0.8-4.5,2
 | 
				
			||||||
 | 
											c-1.2,1.2-1.8,2.9-1.7,4.6c0.1,3.5,3,6.3,6.6,6.2C31.8,35.2,32.5,35.2,33.2,35.2z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st3" d="M33.2,60.5c26.7,0,48.5,21.7,48.5,48.5c0,0.6,0,1.3,0,2c-0.1,1.7,0.5,3.3,1.7,4.6c1.2,1.3,2.7,2,4.4,2.1
 | 
				
			||||||
 | 
											c1.7,0.1,3.3-0.5,4.6-1.7c1.2-1.2,2-2.7,2-4.4c0-0.9,0.1-1.8,0.1-2.6c0-33.8-27.5-61.2-61.2-61.2c-0.8,0-1.6,0-2.6,0.1
 | 
				
			||||||
 | 
											c-1.7,0.1-3.3,0.8-4.4,2.1c-1.2,1.3-1.8,2.9-1.7,4.6s0.8,3.3,2.1,4.4c1.3,1.2,2.9,1.8,4.6,1.7C31.9,60.5,32.6,60.5,33.2,60.5z"
 | 
				
			||||||
 | 
											/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<g>
 | 
				
			||||||
 | 
									<g>
 | 
				
			||||||
 | 
										<path class="st4" d="M33.2,86.7c12.3,0,22.3,10,22.3,22.3c0,0.5,0,1.1-0.1,1.8c-0.3,3.5,2.3,6.6,5.8,6.9
 | 
				
			||||||
 | 
											c3.5,0.3,6.6-2.3,6.9-5.8c0.1-1,0.1-1.9,0.1-2.8c0-19.3-15.7-35.1-35.1-35.1c-0.9,0-1.8,0-2.8,0.1c-1.7,0.1-3.2,0.9-4.3,2.2
 | 
				
			||||||
 | 
											c-1.1,1.3-1.6,2.9-1.5,4.6c0.1,1.7,0.9,3.2,2.2,4.3c1.3,1.1,2.9,1.6,4.6,1.5C32.1,86.7,32.7,86.7,33.2,86.7z"/>
 | 
				
			||||||
 | 
									</g>
 | 
				
			||||||
 | 
								</g>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
						</g>
 | 
				
			||||||
 | 
						<g>
 | 
				
			||||||
 | 
							<path class="st1" d="M35.8,130.4c1.1,0.6,2.1,1.5,2.7,2.6c0.7,1.1,1,2.3,1,3.7s-0.3,2.6-1,3.7c-0.7,1.1-1.6,2-2.7,2.6
 | 
				
			||||||
 | 
								c-1.1,0.6-2.4,1-3.8,1s-2.7-0.3-3.8-1c-1.1-0.6-2.1-1.5-2.7-2.6c-0.7-1.1-1-2.3-1-3.7c0-1.3,0.3-2.6,1-3.7c0.7-1.1,1.6-2,2.7-2.6
 | 
				
			||||||
 | 
								c1.1-0.6,2.4-0.9,3.8-0.9C33.4,129.5,34.7,129.8,35.8,130.4z M29.9,132.9c-0.7,0.4-1.2,0.9-1.6,1.6s-0.6,1.4-0.6,2.2
 | 
				
			||||||
 | 
								c0,0.8,0.2,1.6,0.6,2.3c0.4,0.7,0.9,1.2,1.6,1.6c0.7,0.4,1.4,0.6,2.1,0.6c0.8,0,1.5-0.2,2.1-0.6c0.6-0.4,1.2-0.9,1.5-1.6
 | 
				
			||||||
 | 
								c0.4-0.7,0.6-1.4,0.6-2.3c0-0.8-0.2-1.6-0.6-2.2s-0.9-1.2-1.5-1.6c-0.6-0.4-1.4-0.6-2.1-0.6C31.3,132.3,30.6,132.5,29.9,132.9z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M50.6,133.6c0.8,0.5,1.4,1.1,1.8,2c0.4,0.8,0.6,1.8,0.6,2.9c0,1.1-0.2,2-0.6,2.8c-0.4,0.8-1,1.5-1.8,1.9
 | 
				
			||||||
 | 
								c-0.8,0.5-1.6,0.7-2.6,0.7c-0.7,0-1.4-0.1-2-0.4s-1.1-0.7-1.5-1.2v5.4h-3.1V133h3.1v1.6c0.4-0.5,0.9-1,1.4-1.2s1.2-0.4,2-0.4
 | 
				
			||||||
 | 
								C48.9,132.9,49.8,133.1,50.6,133.6z M49.1,140.5c0.5-0.6,0.7-1.3,0.7-2.2c0-0.9-0.2-1.6-0.7-2.1c-0.5-0.6-1.1-0.8-1.9-0.8
 | 
				
			||||||
 | 
								s-1.4,0.3-1.9,0.8c-0.5,0.6-0.8,1.3-0.8,2.1c0,0.9,0.2,1.6,0.8,2.2s1.1,0.8,1.9,0.8S48.6,141,49.1,140.5z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M63.4,134.4c0.9,1,1.4,2.4,1.4,4.2c0,0.3,0,0.6,0,0.7H57c0.2,0.7,0.5,1.2,1,1.6c0.5,0.4,1.1,0.6,1.8,0.6
 | 
				
			||||||
 | 
								c0.5,0,1-0.1,1.5-0.3s0.9-0.5,1.3-0.9l1.6,1.6c-0.5,0.6-1.2,1.1-2,1.4c-0.8,0.3-1.6,0.5-2.6,0.5c-1.1,0-2.1-0.2-3-0.7
 | 
				
			||||||
 | 
								s-1.5-1.1-2-1.9c-0.5-0.8-0.7-1.8-0.7-2.9c0-1.1,0.2-2.1,0.7-2.9s1.1-1.5,2-1.9c0.8-0.5,1.8-0.7,2.9-0.7
 | 
				
			||||||
 | 
								C61.2,132.9,62.5,133.4,63.4,134.4z M61.8,137.5c0-0.7-0.3-1.3-0.7-1.7s-1-0.6-1.7-0.6c-0.7,0-1.2,0.2-1.7,0.6
 | 
				
			||||||
 | 
								c-0.4,0.4-0.7,1-0.9,1.7H61.8z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M76.2,134c0.7,0.7,1.1,1.7,1.1,3v6.8h-3.1v-5.9c0-0.7-0.2-1.2-0.6-1.6s-0.9-0.6-1.5-0.6
 | 
				
			||||||
 | 
								c-0.8,0-1.4,0.3-1.8,0.8c-0.4,0.5-0.7,1.2-0.7,2v5.3h-3.1V133h3.1v1.9c0.7-1.3,2-2,3.7-2C74.6,132.8,75.5,133.2,76.2,134z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M96,129.7h3.3l-4.7,14h-3.3l-2.9-10.1l-3,10.1h-3.2l-4.7-14h3.4l3,10.7l3-10.7H90l3.1,10.7L96,129.7z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M103.3,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
 | 
				
			||||||
 | 
								c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C102.6,128.2,103,128.3,103.3,128.7z M100.6,133h3.1
 | 
				
			||||||
 | 
								v10.8h-3.1V133z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M106.5,129.7h10.1l0,2.6h-6.9v3.4h6.3v2.6h-6.3v5.3h-3.2V129.7z"/>
 | 
				
			||||||
 | 
							<path class="st1" d="M120.9,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
 | 
				
			||||||
 | 
								c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C120.1,128.2,120.5,128.3,120.9,128.7z M118.1,133h3.1
 | 
				
			||||||
 | 
								v10.8h-3.1V133z"/>
 | 
				
			||||||
 | 
						</g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 8.0 KiB  | 
@@ -17,6 +17,7 @@ servers:
 | 
				
			|||||||
security:
 | 
					security:
 | 
				
			||||||
  - bearerAuth: []
 | 
					  - bearerAuth: []
 | 
				
			||||||
  - ApiKeyAuth: []
 | 
					  - ApiKeyAuth: []
 | 
				
			||||||
 | 
					  - ApiToken: []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
components:
 | 
					components:
 | 
				
			||||||
  securitySchemes:
 | 
					  securitySchemes:
 | 
				
			||||||
@@ -28,6 +29,10 @@ components:
 | 
				
			|||||||
      type: http
 | 
					      type: http
 | 
				
			||||||
      scheme: bearer
 | 
					      scheme: bearer
 | 
				
			||||||
      bearerFormat: JWT
 | 
					      bearerFormat: JWT
 | 
				
			||||||
 | 
					    ApiToken:
 | 
				
			||||||
 | 
					      type: apiKey
 | 
				
			||||||
 | 
					      in: header
 | 
				
			||||||
 | 
					      name: X-API-TOKEN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  responses:
 | 
					  responses:
 | 
				
			||||||
    NotFound:
 | 
					    NotFound:
 | 
				
			||||||
@@ -66,7 +71,8 @@ components:
 | 
				
			|||||||
                  - 11    # BAD_MFA_TRANSACTION
 | 
					                  - 11    # BAD_MFA_TRANSACTION
 | 
				
			||||||
                  - 12    # MFA_FAILURE
 | 
					                  - 12    # MFA_FAILURE
 | 
				
			||||||
                  - 13    # SECURITY_SERVICE_UNREACHABLE
 | 
					                  - 13    # SECURITY_SERVICE_UNREACHABLE
 | 
				
			||||||
                  - 14    # CANNOT REFRESH TOKEN
 | 
					                  - 14    # CANNOT_REFRESH_TOKEN
 | 
				
			||||||
 | 
					                  - 15    # ACCOUNT_SUSPENDED
 | 
				
			||||||
              ErrorDetails:
 | 
					              ErrorDetails:
 | 
				
			||||||
                type: string
 | 
					                type: string
 | 
				
			||||||
              ErrorDescription:
 | 
					              ErrorDescription:
 | 
				
			||||||
@@ -164,18 +170,61 @@ components:
 | 
				
			|||||||
        aclTemplate:
 | 
					        aclTemplate:
 | 
				
			||||||
          $ref: '#/components/schemas/AclTemplate'
 | 
					          $ref: '#/components/schemas/AclTemplate'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ApiKeyCreationRequest:
 | 
					    ApiKeyAccessRight:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      properties:
 | 
					      properties:
 | 
				
			||||||
 | 
					        service:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					        access:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					          enum:
 | 
				
			||||||
 | 
					            - read
 | 
				
			||||||
 | 
					            - modify
 | 
				
			||||||
 | 
					            - create
 | 
				
			||||||
 | 
					            - delete
 | 
				
			||||||
 | 
					            - noaccess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ApiKeyAccessRightList:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        acls:
 | 
				
			||||||
 | 
					          type: array
 | 
				
			||||||
 | 
					          items:
 | 
				
			||||||
 | 
					            $ref: '#/components/schemas/ApiKeyAccessRight'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ApiKeyEntry:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        id:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					          format: uuid
 | 
				
			||||||
 | 
					        userUuid:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					          format: uuid
 | 
				
			||||||
        name:
 | 
					        name:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
        description:
 | 
					        description:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
 | 
					        apiKey:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					        salt:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
        expiresOn:
 | 
					        expiresOn:
 | 
				
			||||||
          type: integer
 | 
					          type: integer
 | 
				
			||||||
          format: int64
 | 
					          format: int64
 | 
				
			||||||
 | 
					        lastUse:
 | 
				
			||||||
 | 
					          type: integer
 | 
				
			||||||
 | 
					          format: int64
 | 
				
			||||||
        rights:
 | 
					        rights:
 | 
				
			||||||
          $ref: '#/components/schemas/AclTemplate'
 | 
					          $ref: '#/components/schemas/ApiKeyAccessRightList'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ApiKeyEntryList:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        apiKeys:
 | 
				
			||||||
 | 
					          type: array
 | 
				
			||||||
 | 
					          items:
 | 
				
			||||||
 | 
					            $ref: '#/components/schemas/ApiKeyEntry'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ApiKeyCreationAnswer:
 | 
					    ApiKeyCreationAnswer:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
@@ -194,7 +243,7 @@ components:
 | 
				
			|||||||
        apiKey:
 | 
					        apiKey:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
        rights:
 | 
					        rights:
 | 
				
			||||||
          $ref: '#/components/schemas/AclTemplate'
 | 
					          $ref: '#/components/schemas/ApiKeyAccessRightList'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    AclTemplate:
 | 
					    AclTemplate:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
@@ -444,6 +493,16 @@ components:
 | 
				
			|||||||
        sms:
 | 
					        sms:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ExtraSystemConfiguration:
 | 
				
			||||||
 | 
					      type: array
 | 
				
			||||||
 | 
					      items:
 | 
				
			||||||
 | 
					        type: object
 | 
				
			||||||
 | 
					        properties:
 | 
				
			||||||
 | 
					          parameterName:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          parameterValue:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #########################################################################################
 | 
					    #########################################################################################
 | 
				
			||||||
    ##
 | 
					    ##
 | 
				
			||||||
    ## These are endpoints that all services in the uCentral stack must provide
 | 
					    ## These are endpoints that all services in the uCentral stack must provide
 | 
				
			||||||
@@ -506,12 +565,6 @@ components:
 | 
				
			|||||||
            - $ref: '#/components/schemas/StringList'
 | 
					            - $ref: '#/components/schemas/StringList'
 | 
				
			||||||
            - $ref: '#/components/schemas/TagValuePairList'
 | 
					            - $ref: '#/components/schemas/TagValuePairList'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SystemCommandResults:
 | 
					 | 
				
			||||||
      type: object
 | 
					 | 
				
			||||||
      oneOf:
 | 
					 | 
				
			||||||
        - $ref: '#/components/schemas/StringList'
 | 
					 | 
				
			||||||
        - $ref: '#/components/schemas/TagValuePairList'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SystemInfoResults:
 | 
					    SystemInfoResults:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      properties:
 | 
					      properties:
 | 
				
			||||||
@@ -540,6 +593,33 @@ components:
 | 
				
			|||||||
                type: integer
 | 
					                type: integer
 | 
				
			||||||
                format: int64
 | 
					                format: int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SystemResources:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        numberOfFileDescriptors:
 | 
				
			||||||
 | 
					          type: integer
 | 
				
			||||||
 | 
					          format: int64
 | 
				
			||||||
 | 
					        currRealMem:
 | 
				
			||||||
 | 
					          type: integer
 | 
				
			||||||
 | 
					          format: int64
 | 
				
			||||||
 | 
					        peakRealMem:
 | 
				
			||||||
 | 
					          type: integer
 | 
				
			||||||
 | 
					          format: int64
 | 
				
			||||||
 | 
					        currVirtMem:
 | 
				
			||||||
 | 
					          type: integer
 | 
				
			||||||
 | 
					          format: int64
 | 
				
			||||||
 | 
					        peakVirtMem:
 | 
				
			||||||
 | 
					          type: integer
 | 
				
			||||||
 | 
					          format: int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SystemCommandResults:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      oneOf:
 | 
				
			||||||
 | 
					        - $ref: '#/components/schemas/SystemResources'
 | 
				
			||||||
 | 
					        - $ref: '#/components/schemas/SystemInfoResults'
 | 
				
			||||||
 | 
					        - $ref: '#/components/schemas/StringList'
 | 
				
			||||||
 | 
					        - $ref: '#/components/schemas/TagValuePairList'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ProfileAction:
 | 
					    ProfileAction:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      properties:
 | 
					      properties:
 | 
				
			||||||
@@ -704,6 +784,23 @@ components:
 | 
				
			|||||||
              value:
 | 
					              value:
 | 
				
			||||||
                type: string
 | 
					                type: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SystemSecretEntry:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        name:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					        value:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SystemSecretEntryList:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        secrets:
 | 
				
			||||||
 | 
					          type: array
 | 
				
			||||||
 | 
					          items:
 | 
				
			||||||
 | 
					            $ref: '#/components/schemas/SystemSecretEntry'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #########################################################################################
 | 
					    #########################################################################################
 | 
				
			||||||
    ##
 | 
					    ##
 | 
				
			||||||
    ## End of uCentral system wide values
 | 
					    ## End of uCentral system wide values
 | 
				
			||||||
@@ -894,7 +991,7 @@ paths:
 | 
				
			|||||||
  /systemEndpoints:
 | 
					  /systemEndpoints:
 | 
				
			||||||
    get:
 | 
					    get:
 | 
				
			||||||
      tags:
 | 
					      tags:
 | 
				
			||||||
        - Authentication
 | 
					        - System Commands
 | 
				
			||||||
      summary: Retrieve the system layout.
 | 
					      summary: Retrieve the system layout.
 | 
				
			||||||
      operationId: getSystemInfo
 | 
					      operationId: getSystemInfo
 | 
				
			||||||
      responses:
 | 
					      responses:
 | 
				
			||||||
@@ -1034,6 +1131,12 @@ paths:
 | 
				
			|||||||
            type: string
 | 
					            type: string
 | 
				
			||||||
            format: uuid
 | 
					            format: uuid
 | 
				
			||||||
          required: true
 | 
					          required: true
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          description: When used, signifies the the id is actually the email address of the user, and not its uuid
 | 
				
			||||||
 | 
					          name: byEmail
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: boolean
 | 
				
			||||||
 | 
					          required: false
 | 
				
			||||||
      responses:
 | 
					      responses:
 | 
				
			||||||
        200:
 | 
					        200:
 | 
				
			||||||
          $ref: '#/components/schemas/UserInfo'
 | 
					          $ref: '#/components/schemas/UserInfo'
 | 
				
			||||||
@@ -1150,6 +1253,12 @@ paths:
 | 
				
			|||||||
            type: string
 | 
					            type: string
 | 
				
			||||||
            format: uuid
 | 
					            format: uuid
 | 
				
			||||||
          required: true
 | 
					          required: true
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          description: When used, signifies the the id is actually the email address of the user, and not its uuid
 | 
				
			||||||
 | 
					          name: byEmail
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: boolean
 | 
				
			||||||
 | 
					          required: false
 | 
				
			||||||
      responses:
 | 
					      responses:
 | 
				
			||||||
        200:
 | 
					        200:
 | 
				
			||||||
          $ref: '#/components/schemas/UserInfo'
 | 
					          $ref: '#/components/schemas/UserInfo'
 | 
				
			||||||
@@ -1348,7 +1457,7 @@ paths:
 | 
				
			|||||||
  /email:
 | 
					  /email:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      tags:
 | 
					      tags:
 | 
				
			||||||
        - Email
 | 
					        - Messaging
 | 
				
			||||||
      summary: Send test email with the system.
 | 
					      summary: Send test email with the system.
 | 
				
			||||||
      operationId: Send a test email
 | 
					      operationId: Send a test email
 | 
				
			||||||
      requestBody:
 | 
					      requestBody:
 | 
				
			||||||
@@ -1379,7 +1488,7 @@ paths:
 | 
				
			|||||||
  /sms:
 | 
					  /sms:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      tags:
 | 
					      tags:
 | 
				
			||||||
        - Email
 | 
					        - Messaging
 | 
				
			||||||
      summary: Send test email with the system.
 | 
					      summary: Send test email with the system.
 | 
				
			||||||
      operationId: Send a test SMS
 | 
					      operationId: Send a test SMS
 | 
				
			||||||
      parameters:
 | 
					      parameters:
 | 
				
			||||||
@@ -1634,7 +1743,103 @@ paths:
 | 
				
			|||||||
        404:
 | 
					        404:
 | 
				
			||||||
          $ref: '#/components/responses/NotFound'
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /apiKey/{uuid}:
 | 
				
			||||||
 | 
					    get:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - API Tokens
 | 
				
			||||||
 | 
					      summary: Retrieve all the APIKeys for a given user UUID
 | 
				
			||||||
 | 
					      operationId: getApiKeyList
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: path
 | 
				
			||||||
 | 
					          name: uuid
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            format: uuid
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/ApiKeyEntryList'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					    delete:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - API Tokens
 | 
				
			||||||
 | 
					      summary: Retrieve all the APIKeys for a given user UUID
 | 
				
			||||||
 | 
					      operationId: deleteApiKey
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: path
 | 
				
			||||||
 | 
					          name: uuid
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            format: uuid
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          name: keyUuid
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Success'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					    post:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - API Tokens
 | 
				
			||||||
 | 
					      summary: Retrieve all the APIKeys for a given user UUID
 | 
				
			||||||
 | 
					      operationId: createApiKey
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: path
 | 
				
			||||||
 | 
					          name: uuid
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            format: uuid
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					      requestBody:
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: '#/components/schemas/ApiKeyEntry'
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/ApiKeyEntry'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					    put:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - API Tokens
 | 
				
			||||||
 | 
					      summary: Retrieve all the APIKeys for a given user UUID
 | 
				
			||||||
 | 
					      operationId: modifyApiKey
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: path
 | 
				
			||||||
 | 
					          name: uuid
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            format: uuid
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          name: name
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					      requestBody:
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: '#/components/schemas/ApiKeyEntry'
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/ApiKeyEntry'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #########################################################################################
 | 
					  #########################################################################################
 | 
				
			||||||
  ##
 | 
					  ##
 | 
				
			||||||
@@ -1677,19 +1882,6 @@ paths:
 | 
				
			|||||||
  #########################################################################################
 | 
					  #########################################################################################
 | 
				
			||||||
  ##  The following calls are restricted to the private system side APIs
 | 
					  ##  The following calls are restricted to the private system side APIs
 | 
				
			||||||
  #########################################################################################
 | 
					  #########################################################################################
 | 
				
			||||||
  /systemServices:
 | 
					 | 
				
			||||||
    get:
 | 
					 | 
				
			||||||
      tags:
 | 
					 | 
				
			||||||
        - Security
 | 
					 | 
				
			||||||
      summary: Retrieve the basic system information. This information is used between services only.
 | 
					 | 
				
			||||||
      operationId: getSystemServices
 | 
					 | 
				
			||||||
      responses:
 | 
					 | 
				
			||||||
        200:
 | 
					 | 
				
			||||||
          $ref: '#/components/schemas/InternalSystemServices'
 | 
					 | 
				
			||||||
        403:
 | 
					 | 
				
			||||||
          $ref: '#/components/responses/Unauthorized'
 | 
					 | 
				
			||||||
        404:
 | 
					 | 
				
			||||||
          $ref: '#/components/responses/NotFound'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /validateToken:
 | 
					  /validateToken:
 | 
				
			||||||
    get:
 | 
					    get:
 | 
				
			||||||
@@ -1732,6 +1924,26 @@ paths:
 | 
				
			|||||||
        404:
 | 
					        404:
 | 
				
			||||||
          $ref: '#/components/responses/NotFound'
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /validateApiKey:
 | 
				
			||||||
 | 
					    get:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - Security
 | 
				
			||||||
 | 
					      summary: Allows an application to validate an API Key.
 | 
				
			||||||
 | 
					      operationId: validateApiKey
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          name: token
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/TokenValidationResult'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /system:
 | 
					  /system:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      tags:
 | 
					      tags:
 | 
				
			||||||
@@ -1776,21 +1988,167 @@ paths:
 | 
				
			|||||||
            type: string
 | 
					            type: string
 | 
				
			||||||
            enum:
 | 
					            enum:
 | 
				
			||||||
              - info
 | 
					              - info
 | 
				
			||||||
 | 
					              - extraConfiguration
 | 
				
			||||||
 | 
					              - resources
 | 
				
			||||||
          required: true
 | 
					          required: true
 | 
				
			||||||
 | 
					 | 
				
			||||||
      responses:
 | 
					      responses:
 | 
				
			||||||
        200:
 | 
					        200:
 | 
				
			||||||
          description: Successful command execution
 | 
					          $ref: '#/components/schemas/SystemCommandResults'
 | 
				
			||||||
          content:
 | 
					 | 
				
			||||||
            application/json:
 | 
					 | 
				
			||||||
              schema:
 | 
					 | 
				
			||||||
                oneOf:
 | 
					 | 
				
			||||||
                  - $ref: '#/components/schemas/SystemInfoResults'
 | 
					 | 
				
			||||||
        403:
 | 
					        403:
 | 
				
			||||||
          $ref: '#/components/responses/Unauthorized'
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
        404:
 | 
					        404:
 | 
				
			||||||
          $ref: '#/components/responses/NotFound'
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /systemSecret/{secret}:
 | 
				
			||||||
 | 
					    get:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - System Secrets
 | 
				
			||||||
 | 
					      description: Retrieve a specific secret
 | 
				
			||||||
 | 
					      operationId: getSecret
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: path
 | 
				
			||||||
 | 
					          name: secret
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          name: all
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: boolean
 | 
				
			||||||
 | 
					          required: false
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          name: dictionary
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: boolean
 | 
				
			||||||
 | 
					          required: false
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          description: Successfull retrieval
 | 
				
			||||||
 | 
					          content:
 | 
				
			||||||
 | 
					            application/json:
 | 
				
			||||||
 | 
					              schema:
 | 
				
			||||||
 | 
					                oneOf:
 | 
				
			||||||
 | 
					                  - type: object
 | 
				
			||||||
 | 
					                    properties:
 | 
				
			||||||
 | 
					                      knownKeys:
 | 
				
			||||||
 | 
					                        type: array
 | 
				
			||||||
 | 
					                        items:
 | 
				
			||||||
 | 
					                          type: object
 | 
				
			||||||
 | 
					                          properties:
 | 
				
			||||||
 | 
					                            key:
 | 
				
			||||||
 | 
					                              type: string
 | 
				
			||||||
 | 
					                            helper:
 | 
				
			||||||
 | 
					                              type: string
 | 
				
			||||||
 | 
					                  - $ref: '#/components/schemas/SystemSecretEntry'
 | 
				
			||||||
 | 
					                  - $ref: '#/components/schemas/SystemSecretEntryList'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    put:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - System Secrets
 | 
				
			||||||
 | 
					      description: Modify a specific secret
 | 
				
			||||||
 | 
					      operationId: modifySecret
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: path
 | 
				
			||||||
 | 
					          name: secret
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          name: value
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/SystemSecretEntry'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    delete:
 | 
				
			||||||
 | 
					      description: Remove a specific secret
 | 
				
			||||||
 | 
					      operationId: deleteSecret
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: path
 | 
				
			||||||
 | 
					          name: secret
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Success'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /systemConfiguration:
 | 
				
			||||||
 | 
					    get:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - SystemConfiguration
 | 
				
			||||||
 | 
					      summary: Retrieve system configuration items
 | 
				
			||||||
 | 
					      operationId: getSystemConfiguration
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          description: Which parameters you want to retrieve
 | 
				
			||||||
 | 
					          name: entries
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            example:
 | 
				
			||||||
 | 
					              - element1
 | 
				
			||||||
 | 
					              - element1,element2,element3
 | 
				
			||||||
 | 
					          required: false
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          description: List of configuration elements
 | 
				
			||||||
 | 
					          content:
 | 
				
			||||||
 | 
					            application/json:
 | 
				
			||||||
 | 
					              schema:
 | 
				
			||||||
 | 
					                type: array
 | 
				
			||||||
 | 
					                items:
 | 
				
			||||||
 | 
					                  $ref: '#/components/schemas/ExtraSystemConfiguration'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    put:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - SystemConfiguration
 | 
				
			||||||
 | 
					      summary: Set some or all system configuration
 | 
				
			||||||
 | 
					      operationId: setSystemConfiguration
 | 
				
			||||||
 | 
					      requestBody:
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: '#/components/schemas/ExtraSystemConfiguration'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/ExtraSystemConfiguration'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    delete:
 | 
				
			||||||
 | 
					      tags:
 | 
				
			||||||
 | 
					        - SystemConfiguration
 | 
				
			||||||
 | 
					      summary: Delete all additional system configuration
 | 
				
			||||||
 | 
					      operationId: deleteSystemConfiguration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        200:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Success'
 | 
				
			||||||
 | 
					        403:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/Unauthorized'
 | 
				
			||||||
 | 
					        404:
 | 
				
			||||||
 | 
					          $ref: '#/components/responses/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#########################################################################################
 | 
					#########################################################################################
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								overlays/curl/portfile.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
 | 
				
			||||||
							
								
								
									
										4
									
								
								overlays/curl/vcpkg.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "name": "curl",
 | 
				
			||||||
 | 
					    "version-string": "7.74.0-1.3+deb11u3"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								overlays/openssl/portfile.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
 | 
				
			||||||
							
								
								
									
										4
									
								
								overlays/openssl/vcpkg.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "name": "openssl",
 | 
				
			||||||
 | 
					    "version-string": "1.1.1n-0+deb11u3"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								overlays/zlib/portfile.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
 | 
				
			||||||
							
								
								
									
										4
									
								
								overlays/zlib/vcpkg.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "name": "zlib",
 | 
				
			||||||
 | 
					    "version-string": "1:1.2.11.dfsg-2+deb11u2"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -34,8 +34,8 @@ authentication.default.username = tip@ucentral.com
 | 
				
			|||||||
authentication.default.password = 13268b7daa751240369d125e79c873bd8dd3bef7981bdfd38ea03dbb1fbe7dcf
 | 
					authentication.default.password = 13268b7daa751240369d125e79c873bd8dd3bef7981bdfd38ea03dbb1fbe7dcf
 | 
				
			||||||
openwifi.system.data = $OWSEC_ROOT/data
 | 
					openwifi.system.data = $OWSEC_ROOT/data
 | 
				
			||||||
openwifi.system.uri.private = https://localhost:17001
 | 
					openwifi.system.uri.private = https://localhost:17001
 | 
				
			||||||
openwifi.system.uri.public = https://local.dpaas.arilia.com:16001
 | 
					openwifi.system.uri.public = https://main.server.com:16001
 | 
				
			||||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
 | 
					openwifi.system.uri.ui = https://ucentral-ui.main.server.com
 | 
				
			||||||
openwifi.security.restapi.disable = false
 | 
					openwifi.security.restapi.disable = false
 | 
				
			||||||
openwifi.system.commandchannel = /tmp/app.ucentralsec
 | 
					openwifi.system.commandchannel = /tmp/app.ucentralsec
 | 
				
			||||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
					openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
				
			||||||
@@ -64,9 +64,19 @@ mailer.loginmethod = login
 | 
				
			|||||||
mailer.port = 587
 | 
					mailer.port = 587
 | 
				
			||||||
mailer.templates = $OWSEC_ROOT/templates
 | 
					mailer.templates = $OWSEC_ROOT/templates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					helper.user.email = openwifi@telecominfraproject.com
 | 
				
			||||||
 | 
					helper.sub.email = openwifi@telecominfraproject.com
 | 
				
			||||||
 | 
					helper.user.global.email = openwifi@telecominfraproject.com
 | 
				
			||||||
 | 
					helper.sub.global.email = openwifi@telecominfraproject.com
 | 
				
			||||||
 | 
					helper.user.site = https://openwifi.telecominfraproject.com
 | 
				
			||||||
 | 
					helper.sub.site = https://openwifi.telecominfraproject.com
 | 
				
			||||||
 | 
					helper.user.login = https://openwifi.telecominfraproject.com
 | 
				
			||||||
 | 
					helper.sub.login = https://openwifi.telecominfraproject.com
 | 
				
			||||||
 | 
					helper.user.signature = Telecom Infra Project
 | 
				
			||||||
 | 
					helper.sub.signature = Telecom Infra Project
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#############################
 | 
					#############################
 | 
				
			||||||
# Generic information for all micro services
 | 
					# Generic information for all micro-services
 | 
				
			||||||
#############################
 | 
					#############################
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# NLB Support
 | 
					# NLB Support
 | 
				
			||||||
@@ -80,7 +90,7 @@ alb.port = 16101
 | 
				
			|||||||
openwifi.kafka.group.id = security
 | 
					openwifi.kafka.group.id = security
 | 
				
			||||||
openwifi.kafka.client.id = security1
 | 
					openwifi.kafka.client.id = security1
 | 
				
			||||||
openwifi.kafka.enable = true
 | 
					openwifi.kafka.enable = true
 | 
				
			||||||
openwifi.kafka.brokerlist = a1.arilia.com:9092
 | 
					openwifi.kafka.brokerlist = kafka:9092
 | 
				
			||||||
openwifi.kafka.auto.commit = false
 | 
					openwifi.kafka.auto.commit = false
 | 
				
			||||||
openwifi.kafka.queue.buffering.max.ms = 50
 | 
					openwifi.kafka.queue.buffering.max.ms = 50
 | 
				
			||||||
openwifi.kafka.ssl.ca.location =
 | 
					openwifi.kafka.ssl.ca.location =
 | 
				
			||||||
@@ -110,18 +120,18 @@ storage.type.sqlite.maxsessions = 128
 | 
				
			|||||||
storage.type.postgresql.maxsessions = 64
 | 
					storage.type.postgresql.maxsessions = 64
 | 
				
			||||||
storage.type.postgresql.idletime = 60
 | 
					storage.type.postgresql.idletime = 60
 | 
				
			||||||
storage.type.postgresql.host = localhost
 | 
					storage.type.postgresql.host = localhost
 | 
				
			||||||
storage.type.postgresql.username = stephb
 | 
					storage.type.postgresql.username = owsec
 | 
				
			||||||
storage.type.postgresql.password = snoopy99
 | 
					storage.type.postgresql.password = owsec
 | 
				
			||||||
storage.type.postgresql.database = ucentral
 | 
					storage.type.postgresql.database = owsec
 | 
				
			||||||
storage.type.postgresql.port = 5432
 | 
					storage.type.postgresql.port = 5432
 | 
				
			||||||
storage.type.postgresql.connectiontimeout = 60
 | 
					storage.type.postgresql.connectiontimeout = 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
storage.type.mysql.maxsessions = 64
 | 
					storage.type.mysql.maxsessions = 64
 | 
				
			||||||
storage.type.mysql.idletime = 60
 | 
					storage.type.mysql.idletime = 60
 | 
				
			||||||
storage.type.mysql.host = localhost
 | 
					storage.type.mysql.host = localhost
 | 
				
			||||||
storage.type.mysql.username = stephb
 | 
					storage.type.mysql.username = owsec
 | 
				
			||||||
storage.type.mysql.password = snoopy99
 | 
					storage.type.mysql.password = owsec
 | 
				
			||||||
storage.type.mysql.database = ucentral
 | 
					storage.type.mysql.database = owsec
 | 
				
			||||||
storage.type.mysql.port = 3306
 | 
					storage.type.mysql.port = 3306
 | 
				
			||||||
storage.type.mysql.connectiontimeout = 60
 | 
					storage.type.mysql.connectiontimeout = 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,6 +64,16 @@ mailer.loginmethod = login
 | 
				
			|||||||
mailer.port = ${MAILER_PORT}
 | 
					mailer.port = ${MAILER_PORT}
 | 
				
			||||||
mailer.templates = ${MAILER_TEMPLATES}
 | 
					mailer.templates = ${MAILER_TEMPLATES}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					helper.user.email = ${USER_HELPER_EMAIL}
 | 
				
			||||||
 | 
					helper.sub.email = ${SUB_HELPER_EMAIL}
 | 
				
			||||||
 | 
					helper.user.global.email = ${GLOBAL_USER_HELPER_EMAIL}
 | 
				
			||||||
 | 
					helper.sub.global.email = ${GLOBAL_SUB_HELPER_EMAIL}
 | 
				
			||||||
 | 
					helper.user.site = ${USER_HELPER_SITE}
 | 
				
			||||||
 | 
					helper.sub.site = ${SUB_HELPER_SITE}
 | 
				
			||||||
 | 
					helper.user.login = ${USER_SYSTEM_LOGIN}
 | 
				
			||||||
 | 
					helper.sub.login = ${SUB_SYSTEM_LOGIN}
 | 
				
			||||||
 | 
					helper.user.signature = ${USER_SIGNATURE}
 | 
				
			||||||
 | 
					helper.sub.signature = ${SUB_SIGNATURE}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#############################
 | 
					#############################
 | 
				
			||||||
# Generic information for all micro services
 | 
					# Generic information for all micro services
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,82 +9,124 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class ACLProcessor {
 | 
						class ACLProcessor {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        enum ACL_OPS {
 | 
							enum ACL_OPS { READ, MODIFY, DELETE, CREATE };
 | 
				
			||||||
            READ,
 | 
							/*
 | 
				
			||||||
            MODIFY,
 | 
							 *  0) You can only delete yourself if you are a subscriber
 | 
				
			||||||
            DELETE,
 | 
								1) You cannot delete yourself
 | 
				
			||||||
            CREATE
 | 
								2) If you are root, you can do anything.
 | 
				
			||||||
        };
 | 
								3) You can do anything to yourself
 | 
				
			||||||
/*
 | 
								4) Nobody can touch a root, unless they are a root, unless it is to get information on a
 | 
				
			||||||
 *  0) You can only delete yourself if you are a subscriber
 | 
							 ROOT 5) Creation rules: ROOT -> create anything PARTNER -> (multi-tenant owner)
 | 
				
			||||||
    1) You cannot delete yourself
 | 
							 admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning ADMIN ->
 | 
				
			||||||
    2) If you are root, you can do anything.
 | 
							 admin-subs-csr-installer-noc-accounting ACCOUNTING -> subs-installer-csr
 | 
				
			||||||
    3) You can do anything to yourself
 | 
					 | 
				
			||||||
    4) Nobody can touch a root, unless they are a root, unless it is to get information on a ROOT
 | 
					 | 
				
			||||||
    5) Creation rules:
 | 
					 | 
				
			||||||
        ROOT -> create anything
 | 
					 | 
				
			||||||
        PARTNER -> (multi-tenant owner) admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning
 | 
					 | 
				
			||||||
        ADMIN -> admin-subs-csr-installer-noc-accounting
 | 
					 | 
				
			||||||
        ACCOUNTING -> subs-installer-csr
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 */
 | 
							 */
 | 
				
			||||||
        static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) {
 | 
							static inline bool Can(const SecurityObjects::UserInfo &User,
 | 
				
			||||||
 | 
												   const SecurityObjects::UserInfo &Target, ACL_OPS Op) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // rule 0
 | 
								switch (Op) {
 | 
				
			||||||
            if(User.id == Target.id && User.userRole == SecurityObjects::SUBSCRIBER && Op == DELETE)
 | 
								case DELETE: {
 | 
				
			||||||
                return true;
 | 
									//  can a user delete themselves - yes - only if not root. We do not want a system
 | 
				
			||||||
 | 
									//  to end up rootless
 | 
				
			||||||
 | 
									if (User.id == Target.id) {
 | 
				
			||||||
 | 
										return User.userRole != SecurityObjects::ROOT;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									//  Root can delete anyone
 | 
				
			||||||
 | 
									switch (User.userRole) {
 | 
				
			||||||
 | 
									case SecurityObjects::ROOT:
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									case SecurityObjects::ADMIN:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT &&
 | 
				
			||||||
 | 
											   Target.userRole != SecurityObjects::PARTNER;
 | 
				
			||||||
 | 
									case SecurityObjects::SUBSCRIBER:
 | 
				
			||||||
 | 
										return User.id == Target.id;
 | 
				
			||||||
 | 
									case SecurityObjects::CSR:
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									case SecurityObjects::SYSTEM:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT &&
 | 
				
			||||||
 | 
											   Target.userRole != SecurityObjects::PARTNER;
 | 
				
			||||||
 | 
									case SecurityObjects::INSTALLER:
 | 
				
			||||||
 | 
										return User.id == Target.id;
 | 
				
			||||||
 | 
									case SecurityObjects::NOC:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::NOC;
 | 
				
			||||||
 | 
									case SecurityObjects::ACCOUNTING:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::ACCOUNTING;
 | 
				
			||||||
 | 
									case SecurityObjects::PARTNER:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT;
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //  rule 1
 | 
								case READ: {
 | 
				
			||||||
            if(User.id == Target.id && Op==DELETE)
 | 
									return User.userRole == SecurityObjects::ROOT ||
 | 
				
			||||||
                return false;
 | 
										   User.userRole == SecurityObjects::ADMIN ||
 | 
				
			||||||
 | 
										   User.userRole == SecurityObjects::PARTNER;
 | 
				
			||||||
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //  rule 2
 | 
								case CREATE: {
 | 
				
			||||||
            if(User.userRole==SecurityObjects::ROOT)
 | 
									switch (User.userRole) {
 | 
				
			||||||
                return true;
 | 
									case SecurityObjects::ROOT:
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									case SecurityObjects::ADMIN:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT &&
 | 
				
			||||||
 | 
											   Target.userRole != SecurityObjects::PARTNER;
 | 
				
			||||||
 | 
									case SecurityObjects::SUBSCRIBER:
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									case SecurityObjects::CSR:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::CSR;
 | 
				
			||||||
 | 
									case SecurityObjects::SYSTEM:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT &&
 | 
				
			||||||
 | 
											   Target.userRole != SecurityObjects::PARTNER;
 | 
				
			||||||
 | 
									case SecurityObjects::INSTALLER:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::INSTALLER;
 | 
				
			||||||
 | 
									case SecurityObjects::NOC:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::NOC;
 | 
				
			||||||
 | 
									case SecurityObjects::ACCOUNTING:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::ACCOUNTING;
 | 
				
			||||||
 | 
									case SecurityObjects::PARTNER:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT;
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //  rule 3
 | 
								case MODIFY: {
 | 
				
			||||||
            if(User.id == Target.id)
 | 
									switch (User.userRole) {
 | 
				
			||||||
                return true;
 | 
									case SecurityObjects::ROOT:
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									case SecurityObjects::ADMIN:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT &&
 | 
				
			||||||
 | 
											   Target.userRole != SecurityObjects::PARTNER;
 | 
				
			||||||
 | 
									case SecurityObjects::SUBSCRIBER:
 | 
				
			||||||
 | 
										return User.id == Target.id;
 | 
				
			||||||
 | 
									case SecurityObjects::CSR:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::CSR;
 | 
				
			||||||
 | 
									case SecurityObjects::SYSTEM:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT &&
 | 
				
			||||||
 | 
											   Target.userRole != SecurityObjects::PARTNER;
 | 
				
			||||||
 | 
									case SecurityObjects::INSTALLER:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::INSTALLER;
 | 
				
			||||||
 | 
									case SecurityObjects::NOC:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::NOC;
 | 
				
			||||||
 | 
									case SecurityObjects::ACCOUNTING:
 | 
				
			||||||
 | 
										return Target.userRole == SecurityObjects::ACCOUNTING;
 | 
				
			||||||
 | 
									case SecurityObjects::PARTNER:
 | 
				
			||||||
 | 
										return Target.userRole != SecurityObjects::ROOT;
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //  rule 4
 | 
						  private:
 | 
				
			||||||
            if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
 | 
						};
 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(Op==CREATE) {
 | 
					} // namespace OpenWifi
 | 
				
			||||||
                if(User.userRole==SecurityObjects::ROOT)
 | 
					 | 
				
			||||||
                    return true;
 | 
					 | 
				
			||||||
                if(User.userRole==SecurityObjects::PARTNER && (Target.userRole==SecurityObjects::ADMIN ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::CSR ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::NOC ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::ACCOUNTING))
 | 
					 | 
				
			||||||
                    return true;
 | 
					 | 
				
			||||||
                if(User.userRole==SecurityObjects::ADMIN &&
 | 
					 | 
				
			||||||
                    (Target.userRole==SecurityObjects::ADMIN ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::CSR ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::NOC ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::ACCOUNTING))
 | 
					 | 
				
			||||||
                    return true;
 | 
					 | 
				
			||||||
                if(User.userRole==SecurityObjects::ACCOUNTING &&
 | 
					 | 
				
			||||||
                    (Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
					 | 
				
			||||||
                    Target.userRole==SecurityObjects::CSR))
 | 
					 | 
				
			||||||
                    return true;
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return true;
 | 
					#endif // OWSEC_ACLPROCESSOR_H
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //OWSEC_ACLPROCESSOR_H
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,124 +3,142 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ActionLinkManager.h"
 | 
					#include "ActionLinkManager.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
					 | 
				
			||||||
#include "MessagingTemplates.h"
 | 
					#include "MessagingTemplates.h"
 | 
				
			||||||
 | 
					#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int ActionLinkManager::Start() {
 | 
						int ActionLinkManager::Start() {
 | 
				
			||||||
        poco_information(Logger(),"Starting...");
 | 
							poco_information(Logger(), "Starting...");
 | 
				
			||||||
        if(!Running_)
 | 
							if (!Running_)
 | 
				
			||||||
            Thr_.start(*this);
 | 
								Thr_.start(*this);
 | 
				
			||||||
        return 0;
 | 
							return 0;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void ActionLinkManager::Stop() {
 | 
				
			||||||
 | 
							poco_information(Logger(), "Stopping...");
 | 
				
			||||||
 | 
							if (Running_) {
 | 
				
			||||||
 | 
								Running_ = false;
 | 
				
			||||||
 | 
								Thr_.wakeUp();
 | 
				
			||||||
 | 
								Thr_.join();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							poco_information(Logger(), "Stopped...");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ActionLinkManager::Stop() {
 | 
					 | 
				
			||||||
        poco_information(Logger(),"Stopping...");
 | 
					 | 
				
			||||||
        if(Running_) {
 | 
					 | 
				
			||||||
            Running_ = false;
 | 
					 | 
				
			||||||
            Thr_.wakeUp();
 | 
					 | 
				
			||||||
            Thr_.join();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        poco_information(Logger(),"Stopped...");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void ActionLinkManager::run() {
 | 
					    void ActionLinkManager::run() {
 | 
				
			||||||
        Running_ = true ;
 | 
							Running_ = true;
 | 
				
			||||||
        Utils::SetThreadName("action-mgr");
 | 
							Utils::SetThreadName("action-mgr");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while(Running_) {
 | 
					        Poco::Thread::trySleep(10000);
 | 
				
			||||||
            Poco::Thread::trySleep(2000);
 | 
					 | 
				
			||||||
            if(!Running_)
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            std::vector<SecurityObjects::ActionLink>    Links;
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                std::lock_guard G(Mutex_);
 | 
					 | 
				
			||||||
                StorageService()->ActionLinksDB().GetActions(Links);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(Links.empty())
 | 
							while (Running_) {
 | 
				
			||||||
                continue;
 | 
								Poco::Thread::trySleep(2000);
 | 
				
			||||||
 | 
								if (!Running_)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								std::vector<SecurityObjects::ActionLink> Links;
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									std::lock_guard G(Mutex_);
 | 
				
			||||||
 | 
									StorageService()->ActionLinksDB().GetActions(Links);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for(auto &i:Links) {
 | 
								if (Links.empty())
 | 
				
			||||||
                if(!Running_)
 | 
									continue;
 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                SecurityObjects::UserInfo UInfo;
 | 
								for (auto &i : Links) {
 | 
				
			||||||
                if((i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD ||
 | 
									if (!Running_)
 | 
				
			||||||
                    i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) && !StorageService()->UserDB().GetUserById(i.userId,UInfo)) {
 | 
										break;
 | 
				
			||||||
                    StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                } else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD ||
 | 
					 | 
				
			||||||
                            i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL ||
 | 
					 | 
				
			||||||
                            i.action==OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP ) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) {
 | 
					 | 
				
			||||||
                    StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                } else if((i.action==OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION) &&
 | 
					 | 
				
			||||||
                        (OpenWifi::Now()-i.created)>(24*60*60)) {
 | 
					 | 
				
			||||||
                    StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                switch(i.action) {
 | 
									SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
                    case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
 | 
									if ((i.action == OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD ||
 | 
				
			||||||
                            if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::FORGOT_PASSWORD)) {
 | 
										 i.action == OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) &&
 | 
				
			||||||
                                poco_information(Logger(),fmt::format("Send password reset link to {}",UInfo.email));
 | 
										!StorageService()->UserDB().GetUserById(i.userId, UInfo)) {
 | 
				
			||||||
                            }
 | 
										StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
				
			||||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
										continue;
 | 
				
			||||||
                        }
 | 
									} else if ((i.action ==
 | 
				
			||||||
                        break;
 | 
													OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD ||
 | 
				
			||||||
 | 
												i.action == OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL ||
 | 
				
			||||||
 | 
												i.action == OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP) &&
 | 
				
			||||||
 | 
											   !StorageService()->SubDB().GetUserById(i.userId, UInfo)) {
 | 
				
			||||||
 | 
										StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									} else if ((i.action == OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION) &&
 | 
				
			||||||
 | 
											   (OpenWifi::Now() - i.created) > (24 * 60 * 60)) {
 | 
				
			||||||
 | 
										StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: {
 | 
									switch (i.action) {
 | 
				
			||||||
                            if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_VERIFICATION)) {
 | 
									case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
 | 
				
			||||||
                                poco_information(Logger(),fmt::format("Send email verification link to {}",UInfo.email));
 | 
										if (AuthService()->SendEmailToUser(i.id, UInfo.email,
 | 
				
			||||||
                            }
 | 
																		   MessagingTemplates::FORGOT_PASSWORD)) {
 | 
				
			||||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
											poco_information(
 | 
				
			||||||
                        }
 | 
												Logger(), fmt::format("Send password reset link to {}", UInfo.email));
 | 
				
			||||||
                        break;
 | 
										}
 | 
				
			||||||
 | 
										StorageService()->ActionLinksDB().SentAction(i.id);
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: {
 | 
									case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: {
 | 
				
			||||||
                            if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_INVITATION)) {
 | 
										if (AuthService()->SendEmailToUser(i.id, UInfo.email,
 | 
				
			||||||
                                poco_information(Logger(),fmt::format("Send new subscriber email invitation link to {}",UInfo.email));
 | 
																		   MessagingTemplates::EMAIL_VERIFICATION)) {
 | 
				
			||||||
                            }
 | 
											poco_information(Logger(), fmt::format("Send email verification link to {}",
 | 
				
			||||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
																				   UInfo.email));
 | 
				
			||||||
                        }
 | 
										}
 | 
				
			||||||
                        break;
 | 
										StorageService()->ActionLinksDB().SentAction(i.id);
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: {
 | 
									case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: {
 | 
				
			||||||
                            auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
 | 
										if (AuthService()->SendEmailToUser(i.id, UInfo.email,
 | 
				
			||||||
                            if(AuthService::SendEmailToSubUser(i.id, UInfo.email,MessagingTemplates::SUB_FORGOT_PASSWORD, Signup.count()==1 ? "" : Signup[0])) {
 | 
																		   MessagingTemplates::EMAIL_INVITATION)) {
 | 
				
			||||||
                                poco_information(Logger(),fmt::format("Send subscriber password reset link to {}",UInfo.email));
 | 
											poco_information(
 | 
				
			||||||
                            }
 | 
												Logger(), fmt::format("Send new subscriber email invitation link to {}",
 | 
				
			||||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
																	  UInfo.email));
 | 
				
			||||||
                        }
 | 
										}
 | 
				
			||||||
                        break;
 | 
										StorageService()->ActionLinksDB().SentAction(i.id);
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
 | 
									case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: {
 | 
				
			||||||
                            auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
 | 
										if (AuthService()->SendEmailToSubUser(i.id, UInfo.email,
 | 
				
			||||||
                            if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
 | 
																			  MessagingTemplates::SUB_FORGOT_PASSWORD,"")) {
 | 
				
			||||||
                                poco_information(Logger(),fmt::format("Send subscriber email verification link to {}",UInfo.email));
 | 
											poco_information(
 | 
				
			||||||
                            }
 | 
												Logger(),
 | 
				
			||||||
                            StorageService()->ActionLinksDB().SentAction(i.id);
 | 
												fmt::format("Send subscriber password reset link to {}", UInfo.email));
 | 
				
			||||||
                        }
 | 
										}
 | 
				
			||||||
                        break;
 | 
										StorageService()->ActionLinksDB().SentAction(i.id);
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
 | 
									case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
 | 
				
			||||||
                        auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
 | 
										if (AuthService()->SendEmailToSubUser(
 | 
				
			||||||
                        if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SIGNUP_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
 | 
												i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION,"")) {
 | 
				
			||||||
                            poco_information(Logger(),fmt::format("Send new subscriber email verification link to {}",UInfo.email));
 | 
											poco_information(
 | 
				
			||||||
                        }
 | 
												Logger(), fmt::format("Send subscriber email verification link to {}",
 | 
				
			||||||
                        StorageService()->ActionLinksDB().SentAction(i.id);
 | 
																	  UInfo.email));
 | 
				
			||||||
                        }
 | 
										}
 | 
				
			||||||
                        break;
 | 
										StorageService()->ActionLinksDB().SentAction(i.id);
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    default: {
 | 
									case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
 | 
				
			||||||
                        StorageService()->ActionLinksDB().SentAction(i.id);
 | 
										auto Signup = Poco::StringTokenizer(UInfo.signingUp, ":");
 | 
				
			||||||
                    }
 | 
										if (AuthService()->SendEmailToSubUser(
 | 
				
			||||||
                }
 | 
												i.id, UInfo.email, MessagingTemplates::SUB_SIGNUP_VERIFICATION,
 | 
				
			||||||
            }
 | 
												Signup.count() == 1 ? "" : Signup[0])) {
 | 
				
			||||||
        }
 | 
											poco_information(
 | 
				
			||||||
    }
 | 
												Logger(),
 | 
				
			||||||
 | 
												fmt::format("Send new subscriber email verification link to {}",
 | 
				
			||||||
 | 
															UInfo.email));
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										StorageService()->ActionLinksDB().SentAction(i.id);
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
									default: {
 | 
				
			||||||
 | 
										StorageService()->ActionLinksDB().SentAction(i.id);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -2,35 +2,29 @@
 | 
				
			|||||||
// Created by stephane bourque on 2021-11-08.
 | 
					// Created by stephane bourque on 2021-11-08.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef OWSEC_ACTIONLINKMANAGER_H
 | 
					#pragma once
 | 
				
			||||||
#define OWSEC_ACTIONLINKMANAGER_H
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/SubSystemServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class ActionLinkManager : public SubSystemServer, Poco::Runnable {
 | 
						class ActionLinkManager : public SubSystemServer, Poco::Runnable {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
 | 
							static ActionLinkManager *instance() {
 | 
				
			||||||
 | 
								static auto instance_ = new ActionLinkManager;
 | 
				
			||||||
 | 
								return instance_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static ActionLinkManager * instance() {
 | 
							int Start() final;
 | 
				
			||||||
            static auto instance_ = new ActionLinkManager;
 | 
							void Stop() final;
 | 
				
			||||||
            return instance_;
 | 
							void run() final;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int Start() final;
 | 
						  private:
 | 
				
			||||||
        void Stop() final;
 | 
							Poco::Thread Thr_;
 | 
				
			||||||
        void run() final;
 | 
							std::atomic_bool Running_ = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
							ActionLinkManager() noexcept
 | 
				
			||||||
        Poco::Thread        Thr_;
 | 
								: SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server") {}
 | 
				
			||||||
        std::atomic_bool    Running_ = false;
 | 
						};
 | 
				
			||||||
 | 
						inline ActionLinkManager *ActionLinkManager() { return ActionLinkManager::instance(); }
 | 
				
			||||||
        ActionLinkManager() noexcept:
 | 
					} // namespace OpenWifi
 | 
				
			||||||
            SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server")
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    inline ActionLinkManager * ActionLinkManager() { return ActionLinkManager::instance(); }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif //OWSEC_ACTIONLINKMANAGER_H
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1438
									
								
								src/AuthService.cpp
									
									
									
									
									
								
							
							
						
						@@ -6,163 +6,229 @@
 | 
				
			|||||||
//	Arilia Wireless Inc.
 | 
					//	Arilia Wireless Inc.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef UCENTRAL_UAUTHSERVICE_H
 | 
					#pragma once
 | 
				
			||||||
#define UCENTRAL_UAUTHSERVICE_H
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <regex>
 | 
					#include <regex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "Poco/Crypto/DigestEngine.h"
 | 
				
			||||||
 | 
					#include "Poco/ExpireLRUCache.h"
 | 
				
			||||||
 | 
					#include "Poco/HMACEngine.h"
 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					#include "Poco/JSON/Object.h"
 | 
				
			||||||
 | 
					#include "Poco/JWT/Signer.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerRequest.h"
 | 
					#include "Poco/Net/HTTPServerRequest.h"
 | 
				
			||||||
#include "Poco/Net/HTTPServerResponse.h"
 | 
					#include "Poco/Net/HTTPServerResponse.h"
 | 
				
			||||||
#include "Poco/JWT/Signer.h"
 | 
					 | 
				
			||||||
#include "Poco/SHA2Engine.h"
 | 
					#include "Poco/SHA2Engine.h"
 | 
				
			||||||
#include "Poco/Crypto/DigestEngine.h"
 | 
					#include "framework/SubSystemServer.h"
 | 
				
			||||||
#include "Poco/HMACEngine.h"
 | 
					
 | 
				
			||||||
#include "Poco/ExpireLRUCache.h"
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
					 | 
				
			||||||
#include "MessagingTemplates.h"
 | 
					#include "MessagingTemplates.h"
 | 
				
			||||||
 | 
					#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi{
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static const std::string AUTHENTICATION_SYSTEM{"SYSTEM"};
 | 
						static const std::string AUTHENTICATION_SYSTEM{"SYSTEM"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class AuthService : public SubSystemServer {
 | 
						class AuthService : public SubSystemServer {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
 | 
							enum ACCESS_TYPE { USERNAME, SERVER, CUSTOM };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        enum ACCESS_TYPE {
 | 
							static ACCESS_TYPE IntToAccessType(int C);
 | 
				
			||||||
            USERNAME,
 | 
							static int AccessTypeToInt(ACCESS_TYPE T);
 | 
				
			||||||
            SERVER,
 | 
					 | 
				
			||||||
            CUSTOM
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static ACCESS_TYPE IntToAccessType(int C);
 | 
							static auto instance() {
 | 
				
			||||||
        static int AccessTypeToInt(ACCESS_TYPE T);
 | 
								static auto instance_ = new AuthService;
 | 
				
			||||||
 | 
								return instance_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static auto instance() {
 | 
							int Start() override;
 | 
				
			||||||
            static auto instance_ = new AuthService;
 | 
							void Stop() override;
 | 
				
			||||||
            return instance_;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int Start() override;
 | 
							[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest &Request,
 | 
				
			||||||
        void Stop() override;
 | 
															std::string &SessionToken,
 | 
				
			||||||
 | 
															SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
 | 
															std::uint64_t TID, bool &Expired);
 | 
				
			||||||
 | 
							[[nodiscard]] bool IsAuthorized(const std::string &SessionToken,
 | 
				
			||||||
 | 
															SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
 | 
															std::uint64_t TID, bool &Expired);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired);
 | 
							[[nodiscard]] UNAUTHORIZED_REASON Authorize(std::string &UserName,
 | 
				
			||||||
        [[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
 | 
																		const std::string &Password,
 | 
				
			||||||
        void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
																		const std::string &NewPassword,
 | 
				
			||||||
        [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
 | 
																		SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
        [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
 | 
																		bool &Expired);
 | 
				
			||||||
        void Logout(const std::string &token, bool EraseFromCache=true);
 | 
							void CreateToken(const std::string &UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
				
			||||||
 | 
							[[nodiscard]] bool SetPassword(const std::string &Password,
 | 
				
			||||||
 | 
														   SecurityObjects::UserInfo &UInfo);
 | 
				
			||||||
 | 
							[[nodiscard]] const std::string &PasswordValidationExpression() const {
 | 
				
			||||||
 | 
								return PasswordValidationStr_;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							void Logout(const std::string &token, bool EraseFromCache = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired);
 | 
							[[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest &Request,
 | 
				
			||||||
        [[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
 | 
															   std::string &SessionToken,
 | 
				
			||||||
        void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
															   SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
        [[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
 | 
															   std::uint64_t TID, bool &Expired);
 | 
				
			||||||
        [[nodiscard]] const std:: string & SubPasswordValidationExpression() const { return PasswordValidationStr_;};
 | 
							[[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub(std::string &UserName,
 | 
				
			||||||
        void SubLogout(const std::string &token, bool EraseFromCache=true);
 | 
																		   const std::string &Password,
 | 
				
			||||||
 | 
																		   const std::string &NewPassword,
 | 
				
			||||||
 | 
																		   SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
 | 
																		   bool &Expired);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void RemoveTokenSystemWide(const std::string &token);
 | 
							void CreateSubToken(const std::string &UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
				
			||||||
 | 
							[[nodiscard]] bool SetSubPassword(const std::string &Password,
 | 
				
			||||||
 | 
															  SecurityObjects::UserInfo &UInfo);
 | 
				
			||||||
 | 
							[[nodiscard]] const std::string &SubPasswordValidationExpression() const {
 | 
				
			||||||
 | 
								return PasswordValidationStr_;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							void SubLogout(const std::string &token, bool EraseFromCache = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool ValidatePassword(const std::string &pwd);
 | 
							void RemoveTokenSystemWide(const std::string &token);
 | 
				
			||||||
        bool ValidateSubPassword(const std::string &pwd);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
 | 
							bool ValidatePassword(const std::string &pwd);
 | 
				
			||||||
        [[nodiscard]] bool IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
 | 
							bool ValidateSubPassword(const std::string &pwd);
 | 
				
			||||||
        [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
 | 
					 | 
				
			||||||
        [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password);
 | 
							[[nodiscard]] bool IsValidToken(const std::string &Token,
 | 
				
			||||||
        [[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
 | 
															SecurityObjects::WebToken &WebToken,
 | 
				
			||||||
        [[nodiscard]] bool ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
 | 
															SecurityObjects::UserInfo &UserInfo, bool &Expired);
 | 
				
			||||||
 | 
							[[nodiscard]] bool IsValidSubToken(const std::string &Token,
 | 
				
			||||||
 | 
															   SecurityObjects::WebToken &WebToken,
 | 
				
			||||||
 | 
															   SecurityObjects::UserInfo &UserInfo, bool &Expired);
 | 
				
			||||||
 | 
							[[nodiscard]] std::string GenerateTokenJWT(const std::string &UserName, ACCESS_TYPE Type);
 | 
				
			||||||
 | 
							[[nodiscard]] std::string GenerateTokenHMAC(const std::string &UserName, ACCESS_TYPE Type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
 | 
							[[nodiscard]] bool IsValidApiKey(const std::string &ApiKey,
 | 
				
			||||||
        [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
 | 
															 SecurityObjects::WebToken &WebToken,
 | 
				
			||||||
 | 
															 SecurityObjects::UserInfo &UserInfo, bool &Expired,
 | 
				
			||||||
 | 
															 std::uint64_t &expiresOn, bool &Suspended);
 | 
				
			||||||
 | 
							[[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName,
 | 
				
			||||||
 | 
																			 const std::string &Password);
 | 
				
			||||||
 | 
							[[nodiscard]] bool ValidatePasswordHash(const std::string &UserName,
 | 
				
			||||||
 | 
																	const std::string &Password,
 | 
				
			||||||
 | 
																	const std::string &StoredPassword);
 | 
				
			||||||
 | 
							[[nodiscard]] bool ValidateSubPasswordHash(const std::string &UserName,
 | 
				
			||||||
 | 
																	   const std::string &Password,
 | 
				
			||||||
 | 
																	   const std::string &StoredPassword);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
 | 
							[[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName,
 | 
				
			||||||
        [[nodiscard]] std::string ResetSubPassword(const std::string &Admin, const std::string &UserName);
 | 
															  const std::string &OldPassword,
 | 
				
			||||||
 | 
															  const std::string &NewPassword);
 | 
				
			||||||
 | 
							[[nodiscard]] std::string ResetPassword(const std::string &Admin,
 | 
				
			||||||
 | 
																	const std::string &UserName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
 | 
							[[nodiscard]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName,
 | 
				
			||||||
        [[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
 | 
																 const std::string &OldPassword,
 | 
				
			||||||
 | 
																 const std::string &NewPassword);
 | 
				
			||||||
 | 
							[[nodiscard]] std::string ResetSubPassword(const std::string &Admin,
 | 
				
			||||||
 | 
																	   const std::string &UserName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason);
 | 
							[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
 | 
				
			||||||
        [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName);
 | 
							[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
 | 
				
			||||||
        [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &code);
 | 
							[[nodiscard]] bool SendEmailToUser(const std::string &LinkId, std::string &Email,
 | 
				
			||||||
 | 
															   MessagingTemplates::EMAIL_REASON Reason);
 | 
				
			||||||
 | 
							[[nodiscard]] bool SendEmailToSubUser(const std::string &LinkId, std::string &Email,
 | 
				
			||||||
 | 
																  MessagingTemplates::EMAIL_REASON Reason,
 | 
				
			||||||
 | 
																  const std::string &OperatorName);
 | 
				
			||||||
 | 
							[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool DeleteUserFromCache(const std::string &UserName);
 | 
							[[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
        bool DeleteSubUserFromCache(const std::string &UserName);
 | 
																	  const std::string &code);
 | 
				
			||||||
        void RevokeToken(std::string & Token);
 | 
					 | 
				
			||||||
        void RevokeSubToken(std::string & Token);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] static inline const std::string GetLogoAssetURI() {
 | 
							bool DeleteUserFromCache(const std::string &UserName);
 | 
				
			||||||
            return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
 | 
							bool DeleteSubUserFromCache(const std::string &UserName);
 | 
				
			||||||
        }
 | 
							void RevokeToken(std::string &Token);
 | 
				
			||||||
 | 
							void RevokeSubToken(std::string &Token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [[nodiscard]] static inline const std::string GetLogoAssetFileName() {
 | 
							[[nodiscard]] static inline const std::string GetLogoAssetURI() {
 | 
				
			||||||
            return MicroService::instance().WWWAssetsDir() + "/the_logo.png";
 | 
								return MicroServicePublicEndPoint() + "/wwwassets/logo.png";
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; }
 | 
							[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
 | 
				
			||||||
        inline const std::string & GetAccessPolicy() const { return AccessPolicy_; }
 | 
								return MicroServiceWWWAssetsDir() + "/logo.png";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
 | 
							[[nodiscard]] static inline const std::string GetSubLogoAssetURI() {
 | 
				
			||||||
        inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; }
 | 
								return MicroServicePublicEndPoint() + "/wwwassets/sub_logo.png";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
 | 
							[[nodiscard]] static inline const std::string GetSubLogoAssetFileName() {
 | 
				
			||||||
        bool RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
 | 
								return MicroServiceWWWAssetsDir() + "/sub_logo.png";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
							inline const std::string &GetPasswordPolicy() const { return PasswordPolicy_; }
 | 
				
			||||||
		Poco::SHA2Engine	SHA2_;
 | 
							inline const std::string &GetAccessPolicy() const { return AccessPolicy_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		std::string         AccessPolicy_;
 | 
							inline const std::string &GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
 | 
				
			||||||
		std::string         PasswordPolicy_;
 | 
							inline const std::string &GetSubAccessPolicy() const { return SubAccessPolicy_; }
 | 
				
			||||||
		std::string         SubAccessPolicy_;
 | 
					 | 
				
			||||||
		std::string         SubPasswordPolicy_;
 | 
					 | 
				
			||||||
		std::string         PasswordValidationStr_;
 | 
					 | 
				
			||||||
        std::string         SubPasswordValidationStr_;
 | 
					 | 
				
			||||||
        std::regex          PasswordValidation_;
 | 
					 | 
				
			||||||
        std::regex          SubPasswordValidation_;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint64_t            TokenAging_ = 15 * 24 * 60 * 60;
 | 
							bool RefreshUserToken(Poco::Net::HTTPServerRequest &Request,
 | 
				
			||||||
        uint64_t            HowManyOldPassword_=5;
 | 
												  const std::string &RefreshToken,
 | 
				
			||||||
        uint64_t            RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60 ;
 | 
												  SecurityObjects::UserInfoAndPolicy &UI);
 | 
				
			||||||
 | 
							bool RefreshSubToken(Poco::Net::HTTPServerRequest &Request, const std::string &RefreshToken,
 | 
				
			||||||
 | 
												 SecurityObjects::UserInfoAndPolicy &UI);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class SHA256Engine : public Poco::Crypto::DigestEngine
 | 
							[[nodiscard]] inline auto HelperEmail() const { return HelperEmail_; };
 | 
				
			||||||
                {
 | 
							[[nodiscard]] inline auto SubHelperEmail() const { return SubHelperEmail_; };
 | 
				
			||||||
                public:
 | 
							[[nodiscard]] inline auto GlobalHelperEmail() const { return GlobalHelperEmail_; };
 | 
				
			||||||
                    enum
 | 
							[[nodiscard]] inline auto GlobalSubHelperEmail() const { return GlobalSubHelperEmail_; };
 | 
				
			||||||
                    {
 | 
							[[nodiscard]] inline auto HelperSite() const { return HelperSite_; };
 | 
				
			||||||
                        BLOCK_SIZE = 64,
 | 
							[[nodiscard]] inline auto SubHelperSite() const { return SubHelperSite_; };
 | 
				
			||||||
                        DIGEST_SIZE = 32
 | 
							[[nodiscard]] inline auto SystemLoginSite() const { return SystemLoginSite_; };
 | 
				
			||||||
                    };
 | 
							[[nodiscard]] inline auto SubSystemLoginSite() const { return SubSystemLoginSite_; };
 | 
				
			||||||
 | 
							[[nodiscard]] inline auto UserSignature() const { return UserSignature_; };
 | 
				
			||||||
 | 
							[[nodiscard]] inline auto SubSignature() const { return SubSignature_; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    SHA256Engine()
 | 
						  private:
 | 
				
			||||||
                    : DigestEngine("SHA256")
 | 
							Poco::SHA2Engine SHA2_;
 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                };
 | 
							std::string AccessPolicy_;
 | 
				
			||||||
 | 
							std::string PasswordPolicy_;
 | 
				
			||||||
 | 
							std::string SubAccessPolicy_;
 | 
				
			||||||
 | 
							std::string SubPasswordPolicy_;
 | 
				
			||||||
 | 
							std::string PasswordValidationStr_;
 | 
				
			||||||
 | 
							std::string SubPasswordValidationStr_;
 | 
				
			||||||
 | 
							std::regex PasswordValidation_;
 | 
				
			||||||
 | 
							std::regex SubPasswordValidation_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::HMACEngine<SHA256Engine> HMAC_{"tipopenwifi"};
 | 
							uint64_t TokenAging_ = 15 * 24 * 60 * 60;
 | 
				
			||||||
 | 
							uint64_t HowManyOldPassword_ = 5;
 | 
				
			||||||
 | 
							uint64_t RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        AuthService() noexcept:
 | 
							std::string HelperEmail_;
 | 
				
			||||||
            SubSystemServer("Authentication", "AUTH-SVR", "authentication")
 | 
							std::string SubHelperEmail_;
 | 
				
			||||||
        {
 | 
							std::string GlobalHelperEmail_;
 | 
				
			||||||
        }
 | 
							std::string GlobalSubHelperEmail_;
 | 
				
			||||||
    };
 | 
							std::string HelperSite_;
 | 
				
			||||||
 | 
							std::string SubHelperSite_;
 | 
				
			||||||
 | 
							std::string SystemLoginSite_;
 | 
				
			||||||
 | 
							std::string SubSystemLoginSite_;
 | 
				
			||||||
 | 
							std::string UserSignature_;
 | 
				
			||||||
 | 
							std::string SubSignature_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline auto AuthService() { return AuthService::instance(); }
 | 
							class SHA256Engine : public Poco::Crypto::DigestEngine {
 | 
				
			||||||
 | 
							  public:
 | 
				
			||||||
 | 
								enum { BLOCK_SIZE = 64, DIGEST_SIZE = 32 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , std::uint64_t TID, bool & Expired, bool Sub ) {
 | 
								SHA256Engine() : DigestEngine("SHA256") {}
 | 
				
			||||||
        if(Sub)
 | 
							};
 | 
				
			||||||
            return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, TID, Expired );
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            return AuthService()->IsAuthorized(Request, SessionToken, UInfo, TID, Expired );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // end of namespace
 | 
							Poco::HMACEngine<SHA256Engine> HMAC_{"tipopenwifi"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif //UCENTRAL_UAUTHSERVICE_H
 | 
							AuthService() noexcept : SubSystemServer("Authentication", "AUTH-SVR", "authentication") {}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inline auto AuthService() { return AuthService::instance(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest &Request,
 | 
				
			||||||
 | 
																		  std::string &SessionToken,
 | 
				
			||||||
 | 
																		  SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
 | 
																		  std::uint64_t TID, bool &Expired, bool Sub) {
 | 
				
			||||||
 | 
							if (Sub)
 | 
				
			||||||
 | 
								return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, TID, Expired);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								return AuthService()->IsAuthorized(Request, SessionToken, UInfo, TID, Expired);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,73 +10,70 @@
 | 
				
			|||||||
//	Arilia Wireless Inc.
 | 
					//	Arilia Wireless Inc.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Poco/Environment.h"
 | 
				
			||||||
#include "Poco/Util/Application.h"
 | 
					#include "Poco/Util/Application.h"
 | 
				
			||||||
#include "Poco/Util/Option.h"
 | 
					#include "Poco/Util/Option.h"
 | 
				
			||||||
#include "Poco/Environment.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Daemon.h"
 | 
					#include "Daemon.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <aws/core/Aws.h>
 | 
					#include <aws/core/Aws.h>
 | 
				
			||||||
#include <aws/s3/model/AccessControlPolicy.h>
 | 
					#include <aws/s3/model/AccessControlPolicy.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "ActionLinkManager.h"
 | 
				
			||||||
#include "SMTPMailerService.h"
 | 
					 | 
				
			||||||
#include "AuthService.h"
 | 
					#include "AuthService.h"
 | 
				
			||||||
#include "SMSSender.h"
 | 
					#include "SMSSender.h"
 | 
				
			||||||
#include "ActionLinkManager.h"
 | 
					#include "SMTPMailerService.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
#include "TotpCache.h"
 | 
					#include "TotpCache.h"
 | 
				
			||||||
 | 
					#include "framework/RESTAPI_RateLimiter.h"
 | 
				
			||||||
 | 
					#include "framework/UI_WebSocketClientServer.h"
 | 
				
			||||||
 | 
					#include <SecretStore.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class Daemon *Daemon::instance_ = nullptr;
 | 
						class Daemon *Daemon::instance_ = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Daemon *Daemon::instance() {
 | 
						class Daemon *Daemon::instance() {
 | 
				
			||||||
        if (instance_ == nullptr) {
 | 
							if (instance_ == nullptr) {
 | 
				
			||||||
            instance_ = new Daemon(vDAEMON_PROPERTIES_FILENAME,
 | 
								instance_ =
 | 
				
			||||||
                                   vDAEMON_ROOT_ENV_VAR,
 | 
									new Daemon(vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR,
 | 
				
			||||||
                                   vDAEMON_CONFIG_ENV_VAR,
 | 
											   vDAEMON_CONFIG_ENV_VAR, vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
 | 
				
			||||||
                                   vDAEMON_APP_NAME,
 | 
											   SubSystemVec{StorageService(), SMSSender(), AuthService(), ActionLinkManager(),
 | 
				
			||||||
                                   vDAEMON_BUS_TIMER,
 | 
															SMTPMailerService(), RESTAPI_RateLimiter(), TotpCache(),
 | 
				
			||||||
                                   SubSystemVec{
 | 
															UI_WebSocketClientServer(), SecretStore()});
 | 
				
			||||||
                                           StorageService(),
 | 
							}
 | 
				
			||||||
                                           SMSSender(),
 | 
							return instance_;
 | 
				
			||||||
                                           ActionLinkManager(),
 | 
						}
 | 
				
			||||||
                                           SMTPMailerService(),
 | 
					 | 
				
			||||||
                                           RESTAPI_RateLimiter(),
 | 
					 | 
				
			||||||
                                           TotpCache(),
 | 
					 | 
				
			||||||
                                           AuthService()
 | 
					 | 
				
			||||||
                                   });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return instance_;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
 | 
						void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
 | 
				
			||||||
        AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
 | 
							AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
						void DaemonPostInitialization(Poco::Util::Application &self) {
 | 
				
			||||||
 | 
							Daemon()->PostInitialization(self);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv) {
 | 
					int main(int argc, char **argv) {
 | 
				
			||||||
    try {
 | 
						try {
 | 
				
			||||||
        SSL_library_init();
 | 
							SSL_library_init();
 | 
				
			||||||
        Aws::SDKOptions AwsOptions;
 | 
							Aws::SDKOptions AwsOptions;
 | 
				
			||||||
        AwsOptions.memoryManagementOptions.memoryManager = nullptr;
 | 
							AwsOptions.memoryManagementOptions.memoryManager = nullptr;
 | 
				
			||||||
        AwsOptions.cryptoOptions.initAndCleanupOpenSSL = false;
 | 
							AwsOptions.cryptoOptions.initAndCleanupOpenSSL = false;
 | 
				
			||||||
        AwsOptions.httpOptions.initAndCleanupCurl = true;
 | 
							AwsOptions.httpOptions.initAndCleanupCurl = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Aws::InitAPI(AwsOptions);
 | 
							Aws::InitAPI(AwsOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int ExitCode=0;
 | 
							int ExitCode = 0;
 | 
				
			||||||
        {
 | 
							{
 | 
				
			||||||
            auto App = OpenWifi::Daemon::instance();
 | 
								auto App = OpenWifi::Daemon::instance();
 | 
				
			||||||
            ExitCode =  App->run(argc, argv);
 | 
								ExitCode = App->run(argc, argv);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        ShutdownAPI(AwsOptions);
 | 
							ShutdownAPI(AwsOptions);
 | 
				
			||||||
        return ExitCode;
 | 
							return ExitCode;
 | 
				
			||||||
    } catch (Poco::Exception &exc) {
 | 
						} catch (Poco::Exception &exc) {
 | 
				
			||||||
        std::cout << exc.displayText() << std::endl;
 | 
							std::cout << exc.displayText() << std::endl;
 | 
				
			||||||
        return Poco::Util::Application::EXIT_SOFTWARE;
 | 
							return Poco::Util::Application::EXIT_SOFTWARE;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
// end of namespace
 | 
					// end of namespace
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										69
									
								
								src/Daemon.h
									
									
									
									
									
								
							
							
						
						@@ -2,57 +2,50 @@
 | 
				
			|||||||
// Created by stephane bourque on 2021-06-10.
 | 
					// Created by stephane bourque on 2021-06-10.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef UCENTRALSEC_DAEMON_H
 | 
					#pragma once
 | 
				
			||||||
#define UCENTRALSEC_DAEMON_H
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <cstdlib>
 | 
					#include <cstdlib>
 | 
				
			||||||
#include <vector>
 | 
					#include <iostream>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceNames.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Poco/Crypto/Cipher.h"
 | 
				
			||||||
 | 
					#include "Poco/Crypto/CipherFactory.h"
 | 
				
			||||||
 | 
					#include "Poco/Crypto/RSAKey.h"
 | 
				
			||||||
 | 
					#include "Poco/ErrorHandler.h"
 | 
				
			||||||
 | 
					#include "Poco/UUIDGenerator.h"
 | 
				
			||||||
#include "Poco/Util/Application.h"
 | 
					#include "Poco/Util/Application.h"
 | 
				
			||||||
#include "Poco/Util/ServerApplication.h"
 | 
					 | 
				
			||||||
#include "Poco/Util/Option.h"
 | 
					#include "Poco/Util/Option.h"
 | 
				
			||||||
#include "Poco/Util/OptionSet.h"
 | 
					#include "Poco/Util/OptionSet.h"
 | 
				
			||||||
#include "Poco/UUIDGenerator.h"
 | 
					#include "Poco/Util/ServerApplication.h"
 | 
				
			||||||
#include "Poco/ErrorHandler.h"
 | 
					 | 
				
			||||||
#include "Poco/Crypto/RSAKey.h"
 | 
					 | 
				
			||||||
#include "Poco/Crypto/CipherFactory.h"
 | 
					 | 
				
			||||||
#include "Poco/Crypto/Cipher.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [[maybe_unused]] static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties";
 | 
						[[maybe_unused]] static const char *vDAEMON_PROPERTIES_FILENAME = "owsec.properties";
 | 
				
			||||||
    [[maybe_unused]] static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT";
 | 
						[[maybe_unused]] static const char *vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT";
 | 
				
			||||||
    [[maybe_unused]] static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG";
 | 
						[[maybe_unused]] static const char *vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG";
 | 
				
			||||||
    [[maybe_unused]] static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str();
 | 
						[[maybe_unused]] static const char *vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str();
 | 
				
			||||||
    [[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 5000;
 | 
						[[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 5000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Daemon : public MicroService {
 | 
						class Daemon : public MicroService {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        explicit Daemon(const std::string & PropFile,
 | 
							explicit Daemon(const std::string &PropFile, const std::string &RootEnv,
 | 
				
			||||||
                        const std::string & RootEnv,
 | 
											const std::string &ConfigEnv, const std::string &AppName, uint64_t BusTimer,
 | 
				
			||||||
                        const std::string & ConfigEnv,
 | 
											const SubSystemVec &SubSystems)
 | 
				
			||||||
                        const std::string & AppName,
 | 
								: MicroService(PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems){};
 | 
				
			||||||
                        uint64_t BusTimer,
 | 
					 | 
				
			||||||
                        const SubSystemVec & SubSystems) :
 | 
					 | 
				
			||||||
                MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void PostInitialization(Poco::Util::Application &self);
 | 
							void PostInitialization(Poco::Util::Application &self);
 | 
				
			||||||
        static Daemon *instance();
 | 
							static Daemon *instance();
 | 
				
			||||||
        inline const std::string & AssetDir() { return AssetDir_; }
 | 
							inline const std::string &AssetDir() { return AssetDir_; }
 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
        static Daemon 		*instance_;
 | 
					 | 
				
			||||||
        std::string         AssetDir_;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline Daemon * Daemon() { return Daemon::instance(); }
 | 
						  private:
 | 
				
			||||||
    inline void DaemonPostInitialization(Poco::Util::Application &self) {
 | 
							static Daemon *instance_;
 | 
				
			||||||
        Daemon()->PostInitialization(self);
 | 
							std::string AssetDir_;
 | 
				
			||||||
    }
 | 
						};
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif //UCENTRALSEC_DAEMON_H
 | 
						inline Daemon *Daemon() { return Daemon::instance(); }
 | 
				
			||||||
 | 
						void DaemonPostInitialization(Poco::Util::Application &self);
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,114 +2,125 @@
 | 
				
			|||||||
// Created by stephane bourque on 2021-10-11.
 | 
					// Created by stephane bourque on 2021-10-11.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "MFAServer.h"
 | 
					#include "MFAServer.h"
 | 
				
			||||||
 | 
					#include "AuthService.h"
 | 
				
			||||||
#include "SMSSender.h"
 | 
					#include "SMSSender.h"
 | 
				
			||||||
#include "SMTPMailerService.h"
 | 
					#include "SMTPMailerService.h"
 | 
				
			||||||
#include "AuthService.h"
 | 
					 | 
				
			||||||
#include "TotpCache.h"
 | 
					#include "TotpCache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int MFAServer::Start() {
 | 
						int MFAServer::Start() { return 0; }
 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void MFAServer::Stop() {
 | 
						void MFAServer::Stop() {}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &ChallengeStart) {
 | 
						bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
        std::lock_guard G(Mutex_);
 | 
														  Poco::JSON::Object &ChallengeStart) {
 | 
				
			||||||
 | 
							std::lock_guard G(Mutex_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CleanCache();
 | 
							CleanCache();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method))
 | 
							if (!MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method))
 | 
				
			||||||
            return false;
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string Challenge = MakeChallenge();
 | 
							std::string Challenge = MakeChallenge();
 | 
				
			||||||
        std::string uuid = MicroService::CreateUUID();
 | 
							std::string uuid = MicroServiceCreateUUID();
 | 
				
			||||||
        uint64_t Created = OpenWifi::Now();
 | 
							uint64_t Created = Utils::Now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ChallengeStart.set("uuid",uuid);
 | 
							ChallengeStart.set("uuid", uuid);
 | 
				
			||||||
        ChallengeStart.set("created", Created);
 | 
							ChallengeStart.set("created", Created);
 | 
				
			||||||
        ChallengeStart.set("question", "mfa challenge");
 | 
							ChallengeStart.set("question", "mfa challenge");
 | 
				
			||||||
        ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
 | 
							ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method };
 | 
							Cache_[uuid] = MFACacheEntry{.UInfo = UInfo,
 | 
				
			||||||
        return SendChallenge(UInfo, UInfo.userinfo.userTypeProprietaryInfo.mfa.method, Challenge);
 | 
														 .Answer = Challenge,
 | 
				
			||||||
    }
 | 
														 .Created = Created,
 | 
				
			||||||
 | 
														 .Method = UInfo.userinfo.userTypeProprietaryInfo.mfa.method};
 | 
				
			||||||
 | 
							return SendChallenge(UInfo, UInfo.userinfo.userTypeProprietaryInfo.mfa.method, Challenge);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) {
 | 
						bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
        if(Method==MFAMETHODS::SMS && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
 | 
													  const std::string &Method, const std::string &Challenge) {
 | 
				
			||||||
            std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen.";
 | 
							if (Method == MFAMETHODS::SMS && SMSSender()->Enabled() &&
 | 
				
			||||||
            return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message);
 | 
								!UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
 | 
				
			||||||
        } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
 | 
								std::string Message = "This is your login code: " + Challenge +
 | 
				
			||||||
            return AuthService()->SendEmailChallengeCode(UInfo,Challenge);
 | 
													  " Please enter this in your login screen.";
 | 
				
			||||||
        } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
 | 
								return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number,
 | 
				
			||||||
            return true;
 | 
														 Message);
 | 
				
			||||||
        }
 | 
							} else if (Method == MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() &&
 | 
				
			||||||
 | 
									   !UInfo.userinfo.email.empty()) {
 | 
				
			||||||
 | 
								return AuthService()->SendEmailChallengeCode(UInfo, Challenge);
 | 
				
			||||||
 | 
							} else if (Method == MFAMETHODS::AUTHENTICATOR &&
 | 
				
			||||||
 | 
									   !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return false;
 | 
							return false;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool MFAServer::ResendCode(const std::string &uuid) {
 | 
						bool MFAServer::ResendCode(const std::string &uuid) {
 | 
				
			||||||
        std::lock_guard G(Mutex_);
 | 
							std::lock_guard G(Mutex_);
 | 
				
			||||||
        auto Hint = Cache_.find(uuid);
 | 
							auto Hint = Cache_.find(uuid);
 | 
				
			||||||
        if(Hint==Cache_.end())
 | 
							if (Hint == Cache_.end())
 | 
				
			||||||
            return false;
 | 
								return false;
 | 
				
			||||||
        return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
 | 
							return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) {
 | 
						bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse,
 | 
				
			||||||
        std::lock_guard G(Mutex_);
 | 
															 SecurityObjects::UserInfoAndPolicy &UInfo) {
 | 
				
			||||||
 | 
							std::lock_guard G(Mutex_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
 | 
							if (!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
 | 
				
			||||||
            return false;
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto uuid = ChallengeResponse->get("uuid").toString();
 | 
							auto uuid = ChallengeResponse->get("uuid").toString();
 | 
				
			||||||
        auto Hint = Cache_.find(uuid);
 | 
							auto Hint = Cache_.find(uuid);
 | 
				
			||||||
        if(Hint == end(Cache_)) {
 | 
							if (Hint == end(Cache_)) {
 | 
				
			||||||
            return false;
 | 
								return false;
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto answer = ChallengeResponse->get("answer").toString();
 | 
							auto answer = ChallengeResponse->get("answer").toString();
 | 
				
			||||||
        std::string Expecting;
 | 
							std::string Expecting;
 | 
				
			||||||
        if(Hint->second.Method==MFAMETHODS::AUTHENTICATOR) {
 | 
							if (Hint->second.Method == MFAMETHODS::AUTHENTICATOR) {
 | 
				
			||||||
            if(!TotpCache()->ValidateCode(Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret,answer, Expecting)) {
 | 
								if (!TotpCache()->ValidateCode(
 | 
				
			||||||
                return false;
 | 
										Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret, answer,
 | 
				
			||||||
            }
 | 
										Expecting)) {
 | 
				
			||||||
        } else if(Hint->second.Answer!=answer) {
 | 
									return false;
 | 
				
			||||||
            return false;
 | 
								}
 | 
				
			||||||
        }
 | 
							} else if (Hint->second.Answer != answer) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        UInfo = Hint->second.UInfo;
 | 
							UInfo = Hint->second.UInfo;
 | 
				
			||||||
        Cache_.erase(Hint);
 | 
							Cache_.erase(Hint);
 | 
				
			||||||
        return true;
 | 
							return true;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool MFAServer::MethodEnabled(const std::string &Method) {
 | 
						bool MFAServer::MethodEnabled(const std::string &Method) {
 | 
				
			||||||
        if(Method==MFAMETHODS::SMS)
 | 
							if (Method == MFAMETHODS::SMS)
 | 
				
			||||||
            return SMSSender()->Enabled();
 | 
								return SMSSender()->Enabled();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(Method==MFAMETHODS::EMAIL)
 | 
							if (Method == MFAMETHODS::EMAIL)
 | 
				
			||||||
            return SMTPMailerService()->Enabled();
 | 
								return SMTPMailerService()->Enabled();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(Method==MFAMETHODS::AUTHENTICATOR)
 | 
							if (Method == MFAMETHODS::AUTHENTICATOR)
 | 
				
			||||||
            return true;
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return false;
 | 
							return false;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void MFAServer::CleanCache() {
 | 
						void MFAServer::CleanCache() {
 | 
				
			||||||
        // it is assumed that you have locked Cache_ at this point.
 | 
							// it is assumed that you have locked Cache_ at this point.
 | 
				
			||||||
        uint64_t Now = OpenWifi::Now();
 | 
							uint64_t Now = Utils::Now();
 | 
				
			||||||
        for(auto i=begin(Cache_);i!=end(Cache_);) {
 | 
							for (auto i = begin(Cache_); i != end(Cache_);) {
 | 
				
			||||||
            if((Now-i->second.Created)>300) {
 | 
								if ((Now - i->second.Created) > 300) {
 | 
				
			||||||
                i = Cache_.erase(i);
 | 
									i = Cache_.erase(i);
 | 
				
			||||||
            } else {
 | 
								} else {
 | 
				
			||||||
                ++i;
 | 
									++i;
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,61 +4,62 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
#include "Poco/JSON/Object.h"
 | 
					#include "Poco/JSON/Object.h"
 | 
				
			||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
					#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					#include "framework/SubSystemServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "fmt/format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    namespace MFAMETHODS {
 | 
						namespace MFAMETHODS {
 | 
				
			||||||
        inline const static std::string SMS{"sms"};
 | 
							inline const static std::string SMS{"sms"};
 | 
				
			||||||
        inline const static std::string EMAIL{"email"};
 | 
							inline const static std::string EMAIL{"email"};
 | 
				
			||||||
        inline const static std::string AUTHENTICATOR{"authenticator"};
 | 
							inline const static std::string AUTHENTICATOR{"authenticator"};
 | 
				
			||||||
        inline const static std::vector<std::string> Methods{ SMS, EMAIL, AUTHENTICATOR };
 | 
							inline const static std::vector<std::string> Methods{SMS, EMAIL, AUTHENTICATOR};
 | 
				
			||||||
        inline bool Validate(const std::string &M) {
 | 
							inline bool Validate(const std::string &M) {
 | 
				
			||||||
            return std::find(cbegin(Methods), cend(Methods),M)!=Methods.end();
 | 
								return std::find(cbegin(Methods), cend(Methods), M) != Methods.end();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
    }
 | 
						} // namespace MFAMETHODS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct MFACacheEntry {
 | 
						struct MFACacheEntry {
 | 
				
			||||||
        SecurityObjects::UserInfoAndPolicy  UInfo;
 | 
							SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
        std::string                         Answer;
 | 
							std::string Answer;
 | 
				
			||||||
        uint64_t                            Created;
 | 
							uint64_t Created;
 | 
				
			||||||
        std::string                         Method;
 | 
							std::string Method;
 | 
				
			||||||
    };
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typedef std::map<std::string, MFACacheEntry> MFAChallengeCache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    typedef std::map<std::string,MFACacheEntry>     MFAChallengeCache;
 | 
						class MFAServer : public SubSystemServer {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							int Start() override;
 | 
				
			||||||
 | 
							void Stop() override;
 | 
				
			||||||
 | 
							static auto instance() {
 | 
				
			||||||
 | 
								static auto instance_ = new MFAServer;
 | 
				
			||||||
 | 
								return instance_;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class MFAServer : public SubSystemServer{
 | 
							bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
    public:
 | 
												   Poco::JSON::Object &Challenge);
 | 
				
			||||||
        int Start() override;
 | 
							bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse,
 | 
				
			||||||
        void Stop() override;
 | 
													  SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
				
			||||||
        static auto instance() {
 | 
							static bool MethodEnabled(const std::string &Method);
 | 
				
			||||||
            static auto instance_ = new MFAServer;
 | 
							bool ResendCode(const std::string &uuid);
 | 
				
			||||||
            return instance_;
 | 
							static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
				
			||||||
        }
 | 
													  const std::string &Method, const std::string &Challenge);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
 | 
							static inline std::string MakeChallenge() {
 | 
				
			||||||
        bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
								return fmt::format("{0:06}", MicroServiceRandom(1, 999999));
 | 
				
			||||||
        static bool MethodEnabled(const std::string &Method);
 | 
							}
 | 
				
			||||||
        bool ResendCode(const std::string &uuid);
 | 
					 | 
				
			||||||
        static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static inline std::string MakeChallenge() {
 | 
						  private:
 | 
				
			||||||
            return fmt::format("{0:06}" , MicroService::instance().Random(1,999999) );
 | 
							MFAChallengeCache Cache_;
 | 
				
			||||||
        }
 | 
							MFAServer() noexcept : SubSystemServer("MFServer", "MFA-SVR", "mfa") {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
							void CleanCache();
 | 
				
			||||||
        MFAChallengeCache   Cache_;
 | 
						};
 | 
				
			||||||
        MFAServer() noexcept:
 | 
					 | 
				
			||||||
            SubSystemServer("MFServer", "MFA-SVR", "mfa")
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void CleanCache();
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    inline auto MFAServer() { return MFAServer::instance(); }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inline auto MFAServer() { return MFAServer::instance(); }
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
// Created by stephane bourque on 2022-07-25.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "MessagingTemplates.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace OpenWifi {
 | 
					 | 
				
			||||||
} // OpenWifi
 | 
					 | 
				
			||||||
@@ -9,67 +9,104 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class MessagingTemplates {
 | 
						class MessagingTemplates {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        static MessagingTemplates & instance() {
 | 
							static MessagingTemplates &instance() {
 | 
				
			||||||
            static auto instance = new MessagingTemplates;
 | 
								static auto instance = new MessagingTemplates;
 | 
				
			||||||
            return *instance;
 | 
								return *instance;
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        enum EMAIL_REASON {
 | 
							enum EMAIL_REASON {
 | 
				
			||||||
            FORGOT_PASSWORD = 0,
 | 
								FORGOT_PASSWORD = 0,
 | 
				
			||||||
            EMAIL_VERIFICATION,
 | 
								EMAIL_VERIFICATION,
 | 
				
			||||||
            SIGNUP_VERIFICATION,
 | 
								SUB_SIGNUP_VERIFICATION,
 | 
				
			||||||
            EMAIL_INVITATION,
 | 
								EMAIL_INVITATION,
 | 
				
			||||||
            VERIFICATION_CODE,
 | 
								VERIFICATION_CODE,
 | 
				
			||||||
            SUB_FORGOT_PASSWORD,
 | 
								SUB_FORGOT_PASSWORD,
 | 
				
			||||||
            SUB_EMAIL_VERIFICATION,
 | 
								SUB_EMAIL_VERIFICATION,
 | 
				
			||||||
            SUB_VERIFICATION_CODE
 | 
								SUB_VERIFICATION_CODE,
 | 
				
			||||||
        };
 | 
								CERTIFICATE_TRANSFER_NOTIFICATION,
 | 
				
			||||||
 | 
								CERTIFICATE_TRANSFER_AUTHORIZATION,
 | 
				
			||||||
 | 
								CERTIFICATE_DISPUTE_SUCCESS,
 | 
				
			||||||
 | 
								CERTIFICATE_DISPUTE_REJECTED,
 | 
				
			||||||
 | 
								CERTIFICATE_TRANSFER_CANCELED,
 | 
				
			||||||
 | 
								CERTIFICATE_TRANSFER_ACCEPTED,
 | 
				
			||||||
 | 
								CERTIFICATE_TRANSFER_REJECTED
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static std::string AddOperator(const std::string & filename, const std::string &OperatorName) {
 | 
							static std::string AddOperator(const std::string &filename,
 | 
				
			||||||
            if(OperatorName.empty())
 | 
														   const std::string &OperatorName) {
 | 
				
			||||||
                return "/" + filename;
 | 
								if (OperatorName.empty())
 | 
				
			||||||
            return "/" + OperatorName + "/" + filename;
 | 
									return "/" + filename;
 | 
				
			||||||
        }
 | 
								return "/" + OperatorName + "/" + filename;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static std::string TemplateName( EMAIL_REASON r , const std::string &OperatorName="") {
 | 
							static std::string TemplateName(EMAIL_REASON r, const std::string &OperatorName = "") {
 | 
				
			||||||
            switch (r) {
 | 
								switch (r) {
 | 
				
			||||||
                case FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[FORGOT_PASSWORD],OperatorName);
 | 
								case FORGOT_PASSWORD:
 | 
				
			||||||
                case EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION],OperatorName);
 | 
									return AddOperator(EmailTemplateNames[FORGOT_PASSWORD], OperatorName);
 | 
				
			||||||
                case SIGNUP_VERIFICATION: return AddOperator(EmailTemplateNames[SIGNUP_VERIFICATION],OperatorName);
 | 
								case EMAIL_VERIFICATION:
 | 
				
			||||||
                case EMAIL_INVITATION: return AddOperator(EmailTemplateNames[EMAIL_INVITATION],OperatorName);
 | 
									return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION], OperatorName);
 | 
				
			||||||
                case VERIFICATION_CODE: return AddOperator(EmailTemplateNames[VERIFICATION_CODE],OperatorName);
 | 
								case SUB_SIGNUP_VERIFICATION:
 | 
				
			||||||
                case SUB_FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD],OperatorName);
 | 
									return AddOperator(EmailTemplateNames[SUB_SIGNUP_VERIFICATION], OperatorName);
 | 
				
			||||||
                case SUB_EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION],OperatorName);
 | 
								case EMAIL_INVITATION:
 | 
				
			||||||
                case SUB_VERIFICATION_CODE: return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE],OperatorName);
 | 
									return AddOperator(EmailTemplateNames[EMAIL_INVITATION], OperatorName);
 | 
				
			||||||
                default:
 | 
								case VERIFICATION_CODE:
 | 
				
			||||||
                    return "";
 | 
									return AddOperator(EmailTemplateNames[VERIFICATION_CODE], OperatorName);
 | 
				
			||||||
            }
 | 
								case SUB_FORGOT_PASSWORD:
 | 
				
			||||||
        }
 | 
									return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD], OperatorName);
 | 
				
			||||||
 | 
								case SUB_EMAIL_VERIFICATION:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION], OperatorName);
 | 
				
			||||||
 | 
								case SUB_VERIFICATION_CODE:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE], OperatorName);
 | 
				
			||||||
 | 
								case CERTIFICATE_TRANSFER_NOTIFICATION:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_NOTIFICATION],
 | 
				
			||||||
 | 
													   OperatorName);
 | 
				
			||||||
 | 
								case CERTIFICATE_TRANSFER_AUTHORIZATION:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_AUTHORIZATION],
 | 
				
			||||||
 | 
													   OperatorName);
 | 
				
			||||||
 | 
								case CERTIFICATE_DISPUTE_SUCCESS:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[CERTIFICATE_DISPUTE_SUCCESS], OperatorName);
 | 
				
			||||||
 | 
								case CERTIFICATE_DISPUTE_REJECTED:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[CERTIFICATE_DISPUTE_REJECTED], OperatorName);
 | 
				
			||||||
 | 
								case CERTIFICATE_TRANSFER_CANCELED:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_CANCELED], OperatorName);
 | 
				
			||||||
 | 
								case CERTIFICATE_TRANSFER_ACCEPTED:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_ACCEPTED], OperatorName);
 | 
				
			||||||
 | 
								case CERTIFICATE_TRANSFER_REJECTED:
 | 
				
			||||||
 | 
									return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_REJECTED], OperatorName);
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return "";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static std::string Logo(const std::string &OperatorName = "" ) {
 | 
							static std::string Logo(const std::string &OperatorName = "") {
 | 
				
			||||||
            return AddOperator("logo.jpg", OperatorName);
 | 
								return AddOperator("logo.png", OperatorName);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static std::string SubLogo(const std::string &OperatorName = "" ) {
 | 
							static std::string SubLogo(const std::string &OperatorName = "") {
 | 
				
			||||||
            return AddOperator("sub_logo.jpg", OperatorName);
 | 
								return AddOperator("sub_logo.png", OperatorName);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
						  private:
 | 
				
			||||||
        inline const static std::vector<std::string>  EmailTemplateNames = {
 | 
							inline const static std::vector<std::string> EmailTemplateNames = {
 | 
				
			||||||
                "password_reset",
 | 
								"password_reset",
 | 
				
			||||||
                "email_verification",
 | 
								"email_verification",
 | 
				
			||||||
                "signup_verification",
 | 
								"sub_signup_verification",
 | 
				
			||||||
                "email_invitation",
 | 
								"email_invitation",
 | 
				
			||||||
                "verification_code",
 | 
								"verification_code",
 | 
				
			||||||
                "sub_password_reset",
 | 
								"sub_password_reset",
 | 
				
			||||||
                "sub_email_verification",
 | 
								"sub_email_verification",
 | 
				
			||||||
                "sub_verification_code"
 | 
								"sub_verification_code",
 | 
				
			||||||
        };
 | 
								"certificate_transfer_notification",
 | 
				
			||||||
    };
 | 
								"certificate_transfer_authorization",
 | 
				
			||||||
 | 
								"certificate_dispute_success",
 | 
				
			||||||
 | 
								"certificate_dispute_rejected",
 | 
				
			||||||
 | 
								"certificate_transfer_canceled",
 | 
				
			||||||
 | 
								"certificate_transfer_accepted",
 | 
				
			||||||
 | 
								"certificate_transfer_rejected"};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline MessagingTemplates & MessagingTemplates() { return MessagingTemplates::instance(); }
 | 
						inline MessagingTemplates &MessagingTemplates() { return MessagingTemplates::instance(); }
 | 
				
			||||||
 | 
					 | 
				
			||||||
} // OpenWifi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,281 +7,350 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "RESTAPI_action_links.h"
 | 
					#include "RESTAPI_action_links.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/OpenAPIRequests.h"
 | 
				
			||||||
 | 
					#include "framework/RESTAPI_PartHandler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Daemon.h"
 | 
					#include "Daemon.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoGet() {
 | 
					#if defined(TIP_CERT_SERVICE)
 | 
				
			||||||
 | 
						bool ProcessExternalActionLinks(RESTAPIHandler &handler, const std::string &Id,
 | 
				
			||||||
 | 
														const std::string &Action);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto Action = GetParameter("action","");
 | 
						void RESTAPI_action_links::DoGet() {
 | 
				
			||||||
        auto Id = GetParameter("id","");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::ActionLink Link;
 | 
							auto Action = GetParameter("action", "");
 | 
				
			||||||
        if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
 | 
							auto Id = GetParameter("id", "");
 | 
				
			||||||
            return DoReturnA404();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(Action=="password_reset")
 | 
					#if defined(TIP_CERT_SERVICE)
 | 
				
			||||||
            return RequestResetPassword(Link);
 | 
							if (!OpenWifi::ProcessExternalActionLinks(*this, Id, Action)) {
 | 
				
			||||||
        else if(Action=="sub_password_reset")
 | 
								return;
 | 
				
			||||||
            return RequestSubResetPassword(Link);
 | 
							}
 | 
				
			||||||
        else if(Action=="email_verification")
 | 
					#endif
 | 
				
			||||||
            return DoEmailVerification(Link);
 | 
					 | 
				
			||||||
        else if(Action=="sub_email_verification")
 | 
					 | 
				
			||||||
            return DoSubEmailVerification(Link);
 | 
					 | 
				
			||||||
        else if(Action=="signup_verification")
 | 
					 | 
				
			||||||
            return DoNewSubVerification(Link);
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            return DoReturnA404();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoPost() {
 | 
							SecurityObjects::ActionLink Link;
 | 
				
			||||||
        auto Action = GetParameter("action","");
 | 
							if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link))
 | 
				
			||||||
 | 
								return DoReturnA404();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(Action=="password_reset")
 | 
							if (Action == "password_reset")
 | 
				
			||||||
            return CompleteResetPassword();
 | 
								return RequestResetPassword(Link);
 | 
				
			||||||
        else if(Action=="sub_password_reset")
 | 
							else if (Action == "sub_password_reset")
 | 
				
			||||||
            return CompleteResetPassword();
 | 
								return RequestResetPassword(Link);
 | 
				
			||||||
        else if(Action=="signup_completion")
 | 
							else if (Action == "email_verification")
 | 
				
			||||||
            return CompleteSubVerification();
 | 
								return DoEmailVerification(Link);
 | 
				
			||||||
        else if(Action=="email_invitation")
 | 
							else if (Action == "sub_email_verification")
 | 
				
			||||||
            return CompleteEmailInvitation();
 | 
								return DoEmailVerification(Link);
 | 
				
			||||||
        else
 | 
							else if (Action == "signup_verification")
 | 
				
			||||||
            return DoReturnA404();
 | 
								return DoNewSubVerification(Link);
 | 
				
			||||||
    }
 | 
							else
 | 
				
			||||||
 | 
								return DoReturnA404();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
 | 
						void RESTAPI_action_links::DoPost() {
 | 
				
			||||||
        Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}", Request->clientAddress().toString(), Link.userId));
 | 
							auto Action = GetParameter("action", "");
 | 
				
			||||||
        Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"};
 | 
					 | 
				
			||||||
        Types::StringPairVec    FormVars{ {"UUID", Link.id},
 | 
					 | 
				
			||||||
                                          {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
					 | 
				
			||||||
        SendHTMLFileBack(FormFile,FormVars);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoNewSubVerification(SecurityObjects::ActionLink &Link) {
 | 
							if (Action == "password_reset")
 | 
				
			||||||
        Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}", Request->clientAddress().toString(), Link.userId));
 | 
								return CompleteResetPassword();
 | 
				
			||||||
        Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification.html"};
 | 
							else if (Action == "sub_password_reset")
 | 
				
			||||||
        Types::StringPairVec    FormVars{ {"UUID", Link.id},
 | 
								return CompleteResetPassword();
 | 
				
			||||||
                                          {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
							else if (Action == "signup_completion")
 | 
				
			||||||
        SendHTMLFileBack(FormFile,FormVars);
 | 
								return CompleteSubVerification();
 | 
				
			||||||
    }
 | 
							else if (Action == "email_invitation")
 | 
				
			||||||
 | 
								return CompleteEmailInvitation();
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								return DoReturnA404();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::CompleteResetPassword() {
 | 
						void RESTAPI_action_links::AddGlobalVars(Types::StringPairVec &Vars) {
 | 
				
			||||||
        //  form has been posted...
 | 
							Vars.push_back(std::make_pair("USER_HELPER_EMAIL", AuthService()->HelperEmail()));
 | 
				
			||||||
        RESTAPI_PartHandler PartHandler;
 | 
							Vars.push_back(std::make_pair("SUB_HELPER_EMAIL", AuthService()->SubHelperEmail()));
 | 
				
			||||||
        Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
 | 
							Vars.push_back(
 | 
				
			||||||
        if (!Form.empty()) {
 | 
								std::make_pair("GLOBAL_USER_HELPER_EMAIL", AuthService()->GlobalHelperEmail()));
 | 
				
			||||||
 | 
							Vars.push_back(
 | 
				
			||||||
 | 
								std::make_pair("GLOBAL_SUB_HELPER_EMAIL", AuthService()->GlobalSubHelperEmail()));
 | 
				
			||||||
 | 
							Vars.push_back(std::make_pair("USER_HELPER_SITE", AuthService()->HelperSite()));
 | 
				
			||||||
 | 
							Vars.push_back(std::make_pair("SUB_HELPER_SITE", AuthService()->SubHelperSite()));
 | 
				
			||||||
 | 
							Vars.push_back(std::make_pair("USER_SYSTEM_LOGIN", AuthService()->SystemLoginSite()));
 | 
				
			||||||
 | 
							Vars.push_back(std::make_pair("SUB_SYSTEM_LOGIN", AuthService()->SubSystemLoginSite()));
 | 
				
			||||||
 | 
							Vars.push_back(std::make_pair("USER_SIGNATURE", AuthService()->UserSignature()));
 | 
				
			||||||
 | 
							Vars.push_back(std::make_pair("SUB_SIGNATURE", AuthService()->SubSignature()));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            auto Password1 = Form.get("password1","bla");
 | 
						void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
 | 
				
			||||||
            auto Password2 = Form.get("password2","blu");
 | 
							Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}",
 | 
				
			||||||
            auto Id = Form.get("id","");
 | 
															Request->clientAddress().toString(), Link.userId));
 | 
				
			||||||
            auto now = OpenWifi::Now();
 | 
							Poco::File FormFile{Daemon()->AssetDir() + "/password_reset.html"};
 | 
				
			||||||
 | 
							Types::StringPairVec FormVars{
 | 
				
			||||||
 | 
								{"UUID", Link.id},
 | 
				
			||||||
 | 
								{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
				
			||||||
 | 
							AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
							SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SecurityObjects::ActionLink Link;
 | 
						void RESTAPI_action_links::DoNewSubVerification(SecurityObjects::ActionLink &Link) {
 | 
				
			||||||
            if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
 | 
							Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}",
 | 
				
			||||||
                return DoReturnA404();
 | 
															Request->clientAddress().toString(), Link.userId));
 | 
				
			||||||
 | 
							Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification.html"};
 | 
				
			||||||
 | 
							Types::StringPairVec FormVars{
 | 
				
			||||||
 | 
								{"UUID", Link.id},
 | 
				
			||||||
 | 
								{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
				
			||||||
 | 
							AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
							SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(now > Link.expires) {
 | 
						void RESTAPI_action_links::CompleteResetPassword() {
 | 
				
			||||||
                StorageService()->ActionLinksDB().CancelAction(Id);
 | 
							RESTAPI_PartHandler PartHandler;
 | 
				
			||||||
                return DoReturnA404();
 | 
							Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
 | 
				
			||||||
            }
 | 
							if (!Form.empty()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) {
 | 
								auto Password1 = Form.get("password1", "bla");
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
								auto Password2 = Form.get("password2", "blu");
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
								auto Id = Form.get("id", "");
 | 
				
			||||||
                                                  {"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with"
 | 
								auto now = OpenWifi::Now();
 | 
				
			||||||
                                                                 " accepted password creation restrictions. Please consult our on-line help"
 | 
					 | 
				
			||||||
                                                                 " to look at the our password policy. If you would like to contact us, please mention"
 | 
					 | 
				
			||||||
                                                                 " id(" + Id + ")"}};
 | 
					 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SecurityObjects::UserInfo   UInfo;
 | 
								SecurityObjects::ActionLink Link;
 | 
				
			||||||
 | 
								if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link))
 | 
				
			||||||
 | 
									return DoReturnA404();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
 | 
								if (now > Link.expires) {
 | 
				
			||||||
            if(!Found) {
 | 
									StorageService()->ActionLinksDB().CancelAction(Id);
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
									return DoReturnA404();
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
								}
 | 
				
			||||||
                                                  {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
 | 
					 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(UInfo.blackListed || UInfo.suspended) {
 | 
								if (Password1 != Password2 || !AuthService()->ValidatePassword(Password2) ||
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
									!AuthService()->ValidatePassword(Password1)) {
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
									Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
				
			||||||
                                                  {"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}};
 | 
									Types::StringPairVec FormVars{
 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
										{"UUID", Id},
 | 
				
			||||||
            }
 | 
										{"ERROR_TEXT",
 | 
				
			||||||
 | 
										 "For some reason, the passwords entered do not match or they do not comply "
 | 
				
			||||||
 | 
										 "with"
 | 
				
			||||||
 | 
										 " accepted password creation restrictions. Please consult our on-line help"
 | 
				
			||||||
 | 
										 " to look at the our password policy. If you would like to contact us, please "
 | 
				
			||||||
 | 
										 "mention"
 | 
				
			||||||
 | 
										 " id(" +
 | 
				
			||||||
 | 
											 Id + ")"}};
 | 
				
			||||||
 | 
									AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
									return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1,UInfo) : AuthService()->SetSubPassword(Password1,UInfo);
 | 
								SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
            if(!GoodPassword) {
 | 
					 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
					 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
					 | 
				
			||||||
                                                  {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
					 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            UInfo.modified = OpenWifi::Now();
 | 
								bool Found = Link.userAction
 | 
				
			||||||
            if(Link.userAction)
 | 
												 ? StorageService()->UserDB().GetUserById(Link.userId, UInfo)
 | 
				
			||||||
                StorageService()->UserDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
 | 
												 : StorageService()->SubDB().GetUserById(Link.userId, UInfo);
 | 
				
			||||||
            else
 | 
								if (!Found) {
 | 
				
			||||||
                StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
 | 
									Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
				
			||||||
 | 
									Types::StringPairVec FormVars{
 | 
				
			||||||
 | 
										{"UUID", Id},
 | 
				
			||||||
 | 
										{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact "
 | 
				
			||||||
 | 
													   "your system administrator."}};
 | 
				
			||||||
 | 
									AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
									return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"};
 | 
								if (UInfo.blackListed || UInfo.suspended) {
 | 
				
			||||||
            Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
									Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
				
			||||||
                                              {"USERNAME", UInfo.email},
 | 
									Types::StringPairVec FormVars{
 | 
				
			||||||
                                              {"ACTION_LINK",MicroService::instance().GetUIURI()}};
 | 
										{"UUID", Id},
 | 
				
			||||||
            StorageService()->ActionLinksDB().CompleteAction(Id);
 | 
										{"ERROR_TEXT", "Please contact our system administrators. We have identified "
 | 
				
			||||||
            SendHTMLFileBack(FormFile,FormVars);
 | 
													   "an error in your account that must be resolved first."}};
 | 
				
			||||||
        } else {
 | 
									AddGlobalVars(FormVars);
 | 
				
			||||||
            DoReturnA404();
 | 
									return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
        }
 | 
								}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::CompleteSubVerification() {
 | 
								bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1, UInfo)
 | 
				
			||||||
        RESTAPI_PartHandler PartHandler;
 | 
																	: AuthService()->SetSubPassword(Password1, UInfo);
 | 
				
			||||||
        Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
 | 
								if (!GoodPassword) {
 | 
				
			||||||
 | 
									Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
				
			||||||
 | 
									Types::StringPairVec FormVars{
 | 
				
			||||||
 | 
										{"UUID", Id}, {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
				
			||||||
 | 
									AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
									return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!Form.empty()) {
 | 
								UInfo.modified = OpenWifi::Now();
 | 
				
			||||||
            auto Password1 = Form.get("password1","bla");
 | 
								if (Link.userAction)
 | 
				
			||||||
            auto Password2 = Form.get("password2","blu");
 | 
									StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
				
			||||||
            auto Id = Form.get("id","");
 | 
								else
 | 
				
			||||||
            auto now = OpenWifi::Now();
 | 
									StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SecurityObjects::ActionLink Link;
 | 
								Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_success.html"};
 | 
				
			||||||
            if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) {
 | 
								Types::StringPairVec FormVars{{"UUID", Id},
 | 
				
			||||||
                return DoReturnA404();
 | 
															  {"USERNAME", UInfo.email},
 | 
				
			||||||
            }
 | 
															  {"ACTION_LINK", MicroService::instance().GetUIURI()}};
 | 
				
			||||||
 | 
								AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
								StorageService()->ActionLinksDB().CompleteAction(Id);
 | 
				
			||||||
 | 
								SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								DoReturnA404();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(now > Link.expires) {
 | 
						void RESTAPI_action_links::CompleteSubVerification() {
 | 
				
			||||||
                StorageService()->ActionLinksDB().CancelAction(Id);
 | 
							RESTAPI_PartHandler PartHandler;
 | 
				
			||||||
                return DoReturnA404();
 | 
							Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(Password1!=Password2 || !AuthService()->ValidateSubPassword(Password1)) {
 | 
							if (!Form.empty()) {
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
								auto Password1 = Form.get("password1", "bla");
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
								auto Password2 = Form.get("password2", "blu");
 | 
				
			||||||
                                                  {"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with"
 | 
								auto Id = Form.get("id", "");
 | 
				
			||||||
                                                                 " accepted password creation restrictions. Please consult our on-line help"
 | 
								auto now = OpenWifi::Now();
 | 
				
			||||||
                                                                 " to look at the our password policy. If you would like to contact us, please mention"
 | 
					 | 
				
			||||||
                                                                 " id(" + Id + ")"}};
 | 
					 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SecurityObjects::UserInfo   UInfo;
 | 
								SecurityObjects::ActionLink Link;
 | 
				
			||||||
            bool Found = StorageService()->SubDB().GetUserById(Link.userId,UInfo);
 | 
								if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link)) {
 | 
				
			||||||
            if(!Found) {
 | 
									return DoReturnA404();
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
 | 
								}
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
					 | 
				
			||||||
                                                  {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
 | 
					 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(UInfo.blackListed || UInfo.suspended) {
 | 
								if (now > Link.expires) {
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
 | 
									StorageService()->ActionLinksDB().CancelAction(Id);
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
									return DoReturnA404();
 | 
				
			||||||
                                                  {"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}};
 | 
								}
 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bool GoodPassword = AuthService()->SetSubPassword(Password1,UInfo);
 | 
								if (Password1 != Password2 || !AuthService()->ValidateSubPassword(Password1)) {
 | 
				
			||||||
            if(!GoodPassword) {
 | 
									Poco::File FormFile{Daemon()->AssetDir() + "/sub_password_reset_error.html"};
 | 
				
			||||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
 | 
									Types::StringPairVec FormVars{
 | 
				
			||||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
										{"UUID", Id},
 | 
				
			||||||
                                                  {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
										{"ERROR_TEXT",
 | 
				
			||||||
                return SendHTMLFileBack(FormFile,FormVars);
 | 
										 "For some reason, the passwords entered do not match or they do not comply "
 | 
				
			||||||
            }
 | 
										 "with"
 | 
				
			||||||
 | 
										 " accepted password creation restrictions. Please consult our on-line help"
 | 
				
			||||||
 | 
										 " to look at the our password policy. If you would like to contact us, please "
 | 
				
			||||||
 | 
										 "mention"
 | 
				
			||||||
 | 
										 " id(" +
 | 
				
			||||||
 | 
											 Id + ")"}};
 | 
				
			||||||
 | 
									AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
									return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            UInfo.modified = OpenWifi::Now();
 | 
								SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
            UInfo.changePassword = false;
 | 
								bool Found = StorageService()->SubDB().GetUserById(Link.userId, UInfo);
 | 
				
			||||||
            UInfo.lastEmailCheck = OpenWifi::Now();
 | 
								if (!Found) {
 | 
				
			||||||
            UInfo.waitingForEmailCheck = false;
 | 
									Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
 | 
				
			||||||
            UInfo.validated = OpenWifi::Now();
 | 
									Types::StringPairVec FormVars{
 | 
				
			||||||
 | 
										{"UUID", Id},
 | 
				
			||||||
 | 
										{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact "
 | 
				
			||||||
 | 
													   "your system administrator."}};
 | 
				
			||||||
 | 
									AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
									return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
 | 
								if (UInfo.blackListed || UInfo.suspended) {
 | 
				
			||||||
 | 
									Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
 | 
				
			||||||
 | 
									Types::StringPairVec FormVars{
 | 
				
			||||||
 | 
										{"UUID", Id},
 | 
				
			||||||
 | 
										{"ERROR_TEXT", "Please contact our system administrators. We have identified "
 | 
				
			||||||
 | 
													   "an error in your account that must be resolved first."}};
 | 
				
			||||||
 | 
									AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
									return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_success.html"};
 | 
								bool GoodPassword = AuthService()->SetSubPassword(Password1, UInfo);
 | 
				
			||||||
            Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
								if (!GoodPassword) {
 | 
				
			||||||
                                              {"USERNAME", UInfo.email} };
 | 
									Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
 | 
				
			||||||
            StorageService()->ActionLinksDB().CompleteAction(Id);
 | 
									Types::StringPairVec FormVars{
 | 
				
			||||||
 | 
										{"UUID", Id}, {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
				
			||||||
 | 
									AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
									return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //  Send the update to the provisioning service
 | 
								UInfo.modified = OpenWifi::Now();
 | 
				
			||||||
            Poco::JSON::Object  Body;
 | 
								UInfo.changePassword = false;
 | 
				
			||||||
            auto RawSignup = Poco::StringTokenizer(UInfo.signingUp,":");
 | 
								UInfo.lastEmailCheck = OpenWifi::Now();
 | 
				
			||||||
            Body.set("signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]);
 | 
								UInfo.waitingForEmailCheck = false;
 | 
				
			||||||
            OpenAPIRequestPut   ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup",
 | 
								UInfo.validated = OpenWifi::Now();
 | 
				
			||||||
                                            {
 | 
					 | 
				
			||||||
                                                {"signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]} ,
 | 
					 | 
				
			||||||
                                                {"operation", "emailVerified"}
 | 
					 | 
				
			||||||
                                            },
 | 
					 | 
				
			||||||
                                            Body,30000);
 | 
					 | 
				
			||||||
            Logger().information(fmt::format("({}): Completed subscriber e-mail verification and password.",UInfo.email));
 | 
					 | 
				
			||||||
            Poco::JSON::Object::Ptr Response;
 | 
					 | 
				
			||||||
            auto Status = ProvRequest.Do(Response);
 | 
					 | 
				
			||||||
            std::stringstream ooo;
 | 
					 | 
				
			||||||
            if(Response!= nullptr)
 | 
					 | 
				
			||||||
                Response->stringify(ooo);
 | 
					 | 
				
			||||||
            Logger().information(fmt::format("({}): Completed subscriber e-mail verification. Provisioning notified, Error={}.",
 | 
					 | 
				
			||||||
                                             UInfo.email, Status));
 | 
					 | 
				
			||||||
            SendHTMLFileBack(FormFile,FormVars);
 | 
					 | 
				
			||||||
            Logger().information(fmt::format("({}): Completed subscriber e-mail verification. FORM notified.",UInfo.email));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            DoReturnA404();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
 | 
								StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
				
			||||||
        auto now = OpenWifi::Now();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(now > Link.expires) {
 | 
								Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_success.html"};
 | 
				
			||||||
            StorageService()->ActionLinksDB().CancelAction(Link.id);
 | 
								Types::StringPairVec FormVars{{"UUID", Id}, {"USERNAME", UInfo.email}};
 | 
				
			||||||
            return DoReturnA404();
 | 
								StorageService()->ActionLinksDB().CompleteAction(Id);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfo UInfo;
 | 
								//  Send the update to the provisioning service
 | 
				
			||||||
        bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
 | 
								Poco::JSON::Object Body;
 | 
				
			||||||
        if (!Found) {
 | 
								auto RawSignup = Poco::StringTokenizer(UInfo.signingUp, ":");
 | 
				
			||||||
            Types::StringPairVec FormVars{{"UUID",       Link.id},
 | 
								Body.set("signupUUID", RawSignup.count() == 1 ? UInfo.signingUp : RawSignup[1]);
 | 
				
			||||||
                                          {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}};
 | 
								OpenAPIRequestPut ProvRequest(
 | 
				
			||||||
            Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
 | 
									uSERVICE_PROVISIONING, "/api/v1/signup",
 | 
				
			||||||
            return SendHTMLFileBack(FormFile, FormVars);
 | 
									{{"signupUUID", RawSignup.count() == 1 ? UInfo.signingUp : RawSignup[1]},
 | 
				
			||||||
        }
 | 
									 {"operation", "emailVerified"}},
 | 
				
			||||||
 | 
									Body, 30000);
 | 
				
			||||||
 | 
								Logger().information(fmt::format(
 | 
				
			||||||
 | 
									"({}): Completed subscriber e-mail verification and password.", UInfo.email));
 | 
				
			||||||
 | 
								Poco::JSON::Object::Ptr Response;
 | 
				
			||||||
 | 
								auto Status = ProvRequest.Do(Response);
 | 
				
			||||||
 | 
								std::stringstream ooo;
 | 
				
			||||||
 | 
								if (Response != nullptr)
 | 
				
			||||||
 | 
									Response->stringify(ooo);
 | 
				
			||||||
 | 
								Logger().information(fmt::format(
 | 
				
			||||||
 | 
									"({}): Completed subscriber e-mail verification. Provisioning notified, Error={}.",
 | 
				
			||||||
 | 
									UInfo.email, Status));
 | 
				
			||||||
 | 
								AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
								SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
								Logger().information(fmt::format(
 | 
				
			||||||
 | 
									"({}): Completed subscriber e-mail verification. FORM notified.", UInfo.email));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								DoReturnA404();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}", Request->clientAddress().toString(),
 | 
						void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
 | 
				
			||||||
                                        UInfo.email));
 | 
							auto now = OpenWifi::Now();
 | 
				
			||||||
        UInfo.waitingForEmailCheck = false;
 | 
					 | 
				
			||||||
        UInfo.validated = true;
 | 
					 | 
				
			||||||
        UInfo.lastEmailCheck = OpenWifi::Now();
 | 
					 | 
				
			||||||
        UInfo.validationDate = OpenWifi::Now();
 | 
					 | 
				
			||||||
        UInfo.modified  = OpenWifi::Now();
 | 
					 | 
				
			||||||
        if(Link.userAction)
 | 
					 | 
				
			||||||
            StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
					 | 
				
			||||||
        Types::StringPairVec FormVars{{"UUID",     Link.id},
 | 
					 | 
				
			||||||
                                      {"USERNAME", UInfo.email},
 | 
					 | 
				
			||||||
                                      {"ACTION_LINK",MicroService::instance().GetUIURI()}};
 | 
					 | 
				
			||||||
        Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
 | 
					 | 
				
			||||||
        StorageService()->ActionLinksDB().CompleteAction(Link.id);
 | 
					 | 
				
			||||||
        SendHTMLFileBack(FormFile, FormVars);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoReturnA404() {
 | 
							if (now > Link.expires) {
 | 
				
			||||||
        Types::StringPairVec FormVars;
 | 
								StorageService()->ActionLinksDB().CancelAction(Link.id);
 | 
				
			||||||
        Poco::File FormFile{Daemon()->AssetDir() + "/404_error.html"};
 | 
								return DoReturnA404();
 | 
				
			||||||
        SendHTMLFileBack(FormFile, FormVars);
 | 
							}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::CompleteEmailInvitation() {
 | 
							SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
        /// TODO:
 | 
							bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId, UInfo)
 | 
				
			||||||
    }
 | 
														 : StorageService()->SubDB().GetUserById(Link.userId, UInfo);
 | 
				
			||||||
 | 
							if (!Found) {
 | 
				
			||||||
 | 
								Types::StringPairVec FormVars{
 | 
				
			||||||
 | 
									{"UUID", Link.id},
 | 
				
			||||||
 | 
									{"ERROR_TEXT", "This does not appear to be a valid email verification link.."}};
 | 
				
			||||||
 | 
								Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
 | 
				
			||||||
 | 
								AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
								return SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::RequestSubResetPassword([[maybe_unused]] SecurityObjects::ActionLink &Link) {
 | 
							Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}",
 | 
				
			||||||
 | 
															Request->clientAddress().toString(), UInfo.email));
 | 
				
			||||||
 | 
							UInfo.waitingForEmailCheck = false;
 | 
				
			||||||
 | 
							UInfo.validated = true;
 | 
				
			||||||
 | 
							UInfo.lastEmailCheck = OpenWifi::Now();
 | 
				
			||||||
 | 
							UInfo.validationDate = OpenWifi::Now();
 | 
				
			||||||
 | 
							UInfo.modified = OpenWifi::Now();
 | 
				
			||||||
 | 
							if (Link.userAction)
 | 
				
			||||||
 | 
								StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
				
			||||||
 | 
							Types::StringPairVec FormVars{{"UUID", Link.id},
 | 
				
			||||||
 | 
														  {"USERNAME", UInfo.email},
 | 
				
			||||||
 | 
														  {"ACTION_LINK", MicroService::instance().GetUIURI()}};
 | 
				
			||||||
 | 
							Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
 | 
				
			||||||
 | 
							AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
							StorageService()->ActionLinksDB().CompleteAction(Link.id);
 | 
				
			||||||
 | 
							SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
						void RESTAPI_action_links::DoReturnA404() {
 | 
				
			||||||
 | 
							Types::StringPairVec FormVars;
 | 
				
			||||||
 | 
							Poco::File FormFile{Daemon()->AssetDir() + "/404_error.html"};
 | 
				
			||||||
 | 
							AddGlobalVars(FormVars);
 | 
				
			||||||
 | 
							SendHTMLFileBack(FormFile, FormVars);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_action_links::DoSubEmailVerification([[maybe_unused]] SecurityObjects::ActionLink &Link) {
 | 
						void RESTAPI_action_links::CompleteEmailInvitation() {
 | 
				
			||||||
 | 
							/// TODO:
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
						void RESTAPI_action_links::RequestSubResetPassword(
 | 
				
			||||||
 | 
							[[maybe_unused]] SecurityObjects::ActionLink &Link) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
						void RESTAPI_action_links::DoSubEmailVerification(
 | 
				
			||||||
 | 
							[[maybe_unused]] SecurityObjects::ActionLink &Link) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,36 +4,35 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_action_links : public RESTAPIHandler {
 | 
						class RESTAPI_action_links : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
                : RESTAPIHandler(bindings, L,
 | 
												 RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
             std::vector<std::string>{
 | 
												 bool Internal)
 | 
				
			||||||
                                        Poco::Net::HTTPRequest::HTTP_GET,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                        Poco::Net::HTTPRequest::HTTP_POST,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
                                        Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                                        Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                        TransactionId,
 | 
												 Server, TransactionId, Internal, false, true,
 | 
				
			||||||
                                        Internal,
 | 
												 RateLimit{.Interval = 1000, .MaxCalls = 10}) {}
 | 
				
			||||||
                                        false,
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; };
 | 
				
			||||||
                                        true, RateLimit{.Interval=1000,.MaxCalls=10}) {}
 | 
							void RequestResetPassword(SecurityObjects::ActionLink &Link);
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; };
 | 
							void RequestSubResetPassword(SecurityObjects::ActionLink &Link);
 | 
				
			||||||
        void RequestResetPassword(SecurityObjects::ActionLink &Link);
 | 
							void CompleteResetPassword();
 | 
				
			||||||
        void RequestSubResetPassword(SecurityObjects::ActionLink &Link);
 | 
							void CompleteSubVerification();
 | 
				
			||||||
        void CompleteResetPassword();
 | 
							void DoEmailVerification(SecurityObjects::ActionLink &Link);
 | 
				
			||||||
        void CompleteSubVerification();
 | 
							void DoSubEmailVerification(SecurityObjects::ActionLink &Link);
 | 
				
			||||||
        void DoEmailVerification(SecurityObjects::ActionLink &Link);
 | 
							void DoReturnA404();
 | 
				
			||||||
        void DoSubEmailVerification(SecurityObjects::ActionLink &Link);
 | 
							void DoNewSubVerification(SecurityObjects::ActionLink &Link);
 | 
				
			||||||
        void DoReturnA404();
 | 
							void CompleteEmailInvitation();
 | 
				
			||||||
        void DoNewSubVerification(SecurityObjects::ActionLink &Link);
 | 
							static void AddGlobalVars(Types::StringPairVec &Vars);
 | 
				
			||||||
        void CompleteEmailInvitation();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoPost() final;
 | 
							void DoPost() final;
 | 
				
			||||||
        void DoDelete() final {};
 | 
							void DoDelete() final{};
 | 
				
			||||||
        void DoPut() final {};
 | 
							void DoPut() final{};
 | 
				
			||||||
    };
 | 
						};
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										165
									
								
								src/RESTAPI/RESTAPI_apiKey_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2022-11-04.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "RESTAPI_apiKey_handler.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void RESTAPI_apiKey_handler::DoGet() {
 | 
				
			||||||
 | 
							std::string user_uuid = GetBinding("uuid", "");
 | 
				
			||||||
 | 
							if (user_uuid.empty()) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (user_uuid != UserInfo_.userinfo.id &&
 | 
				
			||||||
 | 
								UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
 | 
				
			||||||
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SecurityObjects::ApiKeyEntryList List;
 | 
				
			||||||
 | 
							if (DB_.GetRecords(0, 500, List.apiKeys, fmt::format(" userUuid='{}' ", user_uuid))) {
 | 
				
			||||||
 | 
								for (auto &key : List.apiKeys) {
 | 
				
			||||||
 | 
									Sanitize(UserInfo_, key);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								Poco::JSON::Object Answer;
 | 
				
			||||||
 | 
								List.to_json(Answer);
 | 
				
			||||||
 | 
								return ReturnObject(Answer);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return NotFound();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void RESTAPI_apiKey_handler::DoDelete() {
 | 
				
			||||||
 | 
							std::string user_uuid = GetBinding("uuid", "");
 | 
				
			||||||
 | 
							if (user_uuid.empty()) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (user_uuid != UserInfo_.userinfo.id &&
 | 
				
			||||||
 | 
								UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
 | 
				
			||||||
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (user_uuid != UserInfo_.userinfo.id) {
 | 
				
			||||||
 | 
								if (!StorageService()->UserDB().Exists("id", user_uuid)) {
 | 
				
			||||||
 | 
									return NotFound();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::string ApiKeyId = GetParameter("keyUuid", "");
 | 
				
			||||||
 | 
							if (ApiKeyId.empty()) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SecurityObjects::ApiKeyEntry ApiKey;
 | 
				
			||||||
 | 
							if (StorageService()->ApiKeyDB().GetRecord("id", ApiKeyId, ApiKey)) {
 | 
				
			||||||
 | 
								if (ApiKey.userUuid == user_uuid) {
 | 
				
			||||||
 | 
									AuthService()->RemoveTokenSystemWide(ApiKey.apiKey);
 | 
				
			||||||
 | 
									DB_.DeleteRecord("id", ApiKeyId);
 | 
				
			||||||
 | 
									return OK();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return NotFound();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void RESTAPI_apiKey_handler::DoPost() {
 | 
				
			||||||
 | 
							std::string user_uuid = GetBinding("uuid", "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (user_uuid.empty()) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (user_uuid != UserInfo_.userinfo.id &&
 | 
				
			||||||
 | 
								UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
 | 
				
			||||||
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (user_uuid != UserInfo_.userinfo.id) {
 | 
				
			||||||
 | 
								//  Must verify if the user exists
 | 
				
			||||||
 | 
								if (!StorageService()->UserDB().Exists("id", user_uuid)) {
 | 
				
			||||||
 | 
									return BadRequest(RESTAPI::Errors::UserMustExist);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SecurityObjects::ApiKeyEntry NewKey;
 | 
				
			||||||
 | 
							if (!NewKey.from_json(ParsedBody_)) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							NewKey.lastUse = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!Utils::IsAlphaNumeric(NewKey.name) || NewKey.name.empty()) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Poco::toLowerInPlace(NewKey.name);
 | 
				
			||||||
 | 
							NewKey.userUuid = user_uuid;
 | 
				
			||||||
 | 
							if (NewKey.expiresOn < Utils::Now()) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//  does a key of that name already exit for this user?
 | 
				
			||||||
 | 
							SecurityObjects::ApiKeyEntryList ExistingList;
 | 
				
			||||||
 | 
							if (DB_.GetRecords(0, 500, ExistingList.apiKeys,
 | 
				
			||||||
 | 
											   fmt::format(" userUuid='{}' ", user_uuid))) {
 | 
				
			||||||
 | 
								if (std::find_if(ExistingList.apiKeys.begin(), ExistingList.apiKeys.end(),
 | 
				
			||||||
 | 
												 [NewKey](const SecurityObjects::ApiKeyEntry &E) -> bool {
 | 
				
			||||||
 | 
													 return E.name == NewKey.name;
 | 
				
			||||||
 | 
												 }) != ExistingList.apiKeys.end()) {
 | 
				
			||||||
 | 
									return BadRequest(RESTAPI::Errors::ApiKeyNameAlreadyExists);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ExistingList.apiKeys.size() >= 10) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::TooManyApiKeys);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NewKey.id = MicroServiceCreateUUID();
 | 
				
			||||||
 | 
							NewKey.userUuid = user_uuid;
 | 
				
			||||||
 | 
							NewKey.salt = std::to_string(Utils::Now());
 | 
				
			||||||
 | 
							NewKey.apiKey = Utils::ComputeHash(NewKey.salt, UserInfo_.userinfo.id,
 | 
				
			||||||
 | 
															   UserInfo_.webtoken.access_token_);
 | 
				
			||||||
 | 
							NewKey.created = Utils::Now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (DB_.CreateRecord(NewKey)) {
 | 
				
			||||||
 | 
								Poco::JSON::Object Answer;
 | 
				
			||||||
 | 
								NewKey.to_json(Answer);
 | 
				
			||||||
 | 
								return ReturnObject(Answer);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return BadRequest(RESTAPI::Errors::RecordNotCreated);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void RESTAPI_apiKey_handler::DoPut() {
 | 
				
			||||||
 | 
							std::string user_uuid = GetBinding("uuid", "");
 | 
				
			||||||
 | 
							if (user_uuid.empty()) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (user_uuid != UserInfo_.userinfo.id &&
 | 
				
			||||||
 | 
								UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
 | 
				
			||||||
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							SecurityObjects::ApiKeyEntry NewKey;
 | 
				
			||||||
 | 
							if (!NewKey.from_json(ParsedBody_)) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SecurityObjects::ApiKeyEntry ExistingKey;
 | 
				
			||||||
 | 
							if (!DB_.GetRecord("id", NewKey.id, ExistingKey)) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::ApiKeyDoesNotExist);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ExistingKey.userUuid != user_uuid) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							AssignIfPresent(ParsedBody_, "description", ExistingKey.description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (DB_.UpdateRecord("id", ExistingKey.id, ExistingKey)) {
 | 
				
			||||||
 | 
								Poco::JSON::Object Answer;
 | 
				
			||||||
 | 
								ExistingKey.to_json(Answer);
 | 
				
			||||||
 | 
								return ReturnObject(Answer);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							BadRequest(RESTAPI::Errors::RecordNotUpdated);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/RESTAPI/RESTAPI_apiKey_handler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by stephane bourque on 2022-11-04.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
						class RESTAPI_apiKey_handler : public RESTAPIHandler {
 | 
				
			||||||
 | 
						  public:
 | 
				
			||||||
 | 
							RESTAPI_apiKey_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
 | 
												   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
 | 
												   bool Internal)
 | 
				
			||||||
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
 | 
																		  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
				
			||||||
 | 
																		  Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
 | 
																		  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
				
			||||||
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/apiKey/{uuid}"}; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
							ApiKeyDB &DB_ = StorageService()->ApiKeyDB();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void DoGet() final;
 | 
				
			||||||
 | 
							void DoPut() final;
 | 
				
			||||||
 | 
							void DoPost() final;
 | 
				
			||||||
 | 
							void DoDelete() final;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -3,23 +3,23 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTAPI_asset_server.h"
 | 
					#include "RESTAPI_asset_server.h"
 | 
				
			||||||
 | 
					#include "Daemon.h"
 | 
				
			||||||
#include "Poco/File.h"
 | 
					#include "Poco/File.h"
 | 
				
			||||||
#include "framework/ow_constants.h"
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
#include "Daemon.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    void RESTAPI_asset_server::DoGet() {
 | 
						void RESTAPI_asset_server::DoGet() {
 | 
				
			||||||
        Poco::File  AssetFile;
 | 
							Poco::File AssetFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(Request->getURI().find("/favicon.ico") != std::string::npos) {
 | 
							if (Request->getURI().find("/favicon.ico") != std::string::npos) {
 | 
				
			||||||
            AssetFile = Daemon()->AssetDir() + "/favicon.ico";
 | 
								AssetFile = Daemon()->AssetDir() + "/favicon.ico";
 | 
				
			||||||
        } else {
 | 
							} else {
 | 
				
			||||||
            std::string AssetName = GetBinding(RESTAPI::Protocol::ID, "");
 | 
								std::string AssetName = GetBinding(RESTAPI::Protocol::ID, "");
 | 
				
			||||||
            AssetFile = Daemon()->AssetDir() + "/" + AssetName;
 | 
								AssetFile = Daemon()->AssetDir() + "/" + AssetName;
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        if(!AssetFile.isFile()) {
 | 
							if (!AssetFile.isFile()) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        SendFile(AssetFile);
 | 
							SendFile(AssetFile);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,31 +4,29 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_asset_server : public RESTAPIHandler {
 | 
						class RESTAPI_asset_server : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
                : RESTAPIHandler(bindings, L,
 | 
												 RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                                 std::vector<std::string>
 | 
												 bool Internal)
 | 
				
			||||||
                                         {Poco::Net::HTTPRequest::HTTP_POST,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                          Poco::Net::HTTPRequest::HTTP_GET,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                                          Poco::Net::HTTPRequest::HTTP_PUT,
 | 
																		  Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
                                          Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
																		  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
				
			||||||
                                          Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
				
			||||||
                                          Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                          TransactionId,
 | 
												 Server, TransactionId, Internal, false) {}
 | 
				
			||||||
                                          Internal, false) {}
 | 
							static auto PathName() {
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/wwwassets/{id}" ,
 | 
								return std::list<std::string>{"/wwwassets/{id}", "/favicon.ico"};
 | 
				
			||||||
                                                                                         "/favicon.ico"}; };
 | 
							};
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoPost() final {};
 | 
							void DoPost() final{};
 | 
				
			||||||
        void DoDelete() final {};
 | 
							void DoDelete() final{};
 | 
				
			||||||
        void DoPut() final {};
 | 
							void DoPut() final{};
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  private:
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,78 +5,85 @@
 | 
				
			|||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Poco/CountingStream.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/HTMLForm.h"
 | 
				
			||||||
#include "RESTAPI_avatar_handler.h"
 | 
					#include "RESTAPI_avatar_handler.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
#include "Poco/Net/HTMLForm.h"
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void AvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
 | 
						void AvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header,
 | 
				
			||||||
        FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
 | 
														   std::istream &Stream) {
 | 
				
			||||||
        if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
 | 
							FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
 | 
				
			||||||
            std::string Disposition;
 | 
							if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
 | 
				
			||||||
            Poco::Net::NameValueCollection Parameters;
 | 
								std::string Disposition;
 | 
				
			||||||
            Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
 | 
								Poco::Net::NameValueCollection Parameters;
 | 
				
			||||||
            Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
								Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION],
 | 
				
			||||||
        }
 | 
																		  Disposition, Parameters);
 | 
				
			||||||
        Poco::CountingInputStream InputStream(Stream);
 | 
								Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
				
			||||||
        Poco::StreamCopier::copyStream(InputStream, OutputStream_);
 | 
							}
 | 
				
			||||||
        Length_ = OutputStream_.str().size();
 | 
							Poco::CountingInputStream InputStream(Stream);
 | 
				
			||||||
    };
 | 
							Poco::StreamCopier::copyStream(InputStream, OutputStream_);
 | 
				
			||||||
 | 
							Length_ = OutputStream_.str().size();
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_avatar_handler::DoPost() {
 | 
						void RESTAPI_avatar_handler::DoPost() {
 | 
				
			||||||
        std::string Id = UserInfo_.userinfo.id;
 | 
							std::string Id = UserInfo_.userinfo.id;
 | 
				
			||||||
        SecurityObjects::UserInfo UInfo;
 | 
							SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::stringstream SS;
 | 
							std::stringstream SS;
 | 
				
			||||||
        AvatarPartHandler partHandler(Id, Logger_, SS);
 | 
							AvatarPartHandler partHandler(Id, Logger_, SS);
 | 
				
			||||||
        Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
 | 
							Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
 | 
				
			||||||
        Poco::JSON::Object Answer;
 | 
							Poco::JSON::Object Answer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) {
 | 
							if (!partHandler.Name().empty() &&
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
								partHandler.Length() < MicroServiceConfigGetInt("openwifi.avatar.maxsize", 2000000)) {
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
 | 
								Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
				
			||||||
            Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType()));
 | 
								Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
 | 
				
			||||||
            StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email,
 | 
								Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(),
 | 
				
			||||||
                                 Id, SS.str(), partHandler.ContentType(), partHandler.Name());
 | 
																partHandler.ContentType()));
 | 
				
			||||||
            StorageService()->UserDB().SetAvatar(Id,"1");
 | 
								StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email, Id, SS.str(),
 | 
				
			||||||
            Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email));
 | 
																	   partHandler.ContentType(), partHandler.Name());
 | 
				
			||||||
        } else {
 | 
								StorageService()->UserDB().SetAvatar(Id, "1");
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
								Logger().information(fmt::format("Adding avatar for {}", UserInfo_.userinfo.email));
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
 | 
							} else {
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
 | 
								Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
				
			||||||
        }
 | 
								Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
 | 
				
			||||||
        ReturnObject(Answer);
 | 
								Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
 | 
				
			||||||
    }
 | 
							}
 | 
				
			||||||
 | 
							ReturnObject(Answer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_avatar_handler::DoGet() {
 | 
						void RESTAPI_avatar_handler::DoGet() {
 | 
				
			||||||
        std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
							std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
				
			||||||
        if (Id.empty()) {
 | 
							if (Id.empty()) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string Type, Name, AvatarContent;
 | 
							std::string Type, Name, AvatarContent;
 | 
				
			||||||
        if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) {
 | 
							if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent,
 | 
				
			||||||
            return NotFound();
 | 
																		Type, Name)) {
 | 
				
			||||||
        }
 | 
								return NotFound();
 | 
				
			||||||
        Logger().information(fmt::format("Retrieving avatar for {}, size:{}",UserInfo_.userinfo.email,AvatarContent.size()));
 | 
							}
 | 
				
			||||||
        return SendFileContent(AvatarContent, Type, Name);
 | 
							Logger().information(fmt::format("Retrieving avatar for {}, size:{}",
 | 
				
			||||||
    }
 | 
															 UserInfo_.userinfo.email, AvatarContent.size()));
 | 
				
			||||||
 | 
							return SendFileContent(AvatarContent, Type, Name);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_avatar_handler::DoDelete() {
 | 
						void RESTAPI_avatar_handler::DoDelete() {
 | 
				
			||||||
        std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
							std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) {
 | 
							if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT && Id != UserInfo_.userinfo.id) {
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
 | 
							if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email));
 | 
							Logger().information(fmt::format("Deleted avatar for {}", UserInfo_.userinfo.email));
 | 
				
			||||||
        StorageService()->UserDB().SetAvatar(Id,"");
 | 
							StorageService()->UserDB().SetAvatar(Id, "");
 | 
				
			||||||
        OK();
 | 
							OK();
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,51 +3,47 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "Poco/Net/PartHandler.h"
 | 
				
			||||||
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class AvatarPartHandler : public Poco::Net::PartHandler {
 | 
						class AvatarPartHandler : public Poco::Net::PartHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
 | 
							AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream &ofs)
 | 
				
			||||||
                Id_(std::move(Id)),
 | 
								: Id_(std::move(Id)), Logger_(Logger), OutputStream_(ofs) {}
 | 
				
			||||||
                Logger_(Logger),
 | 
							void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
 | 
				
			||||||
                OutputStream_(ofs){
 | 
							[[nodiscard]] uint64_t Length() const { return Length_; }
 | 
				
			||||||
        }
 | 
							[[nodiscard]] std::string &Name() { return Name_; }
 | 
				
			||||||
        void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
 | 
							[[nodiscard]] std::string &ContentType() { return FileType_; }
 | 
				
			||||||
        [[nodiscard]] uint64_t Length() const { return Length_; }
 | 
					 | 
				
			||||||
        [[nodiscard]] std::string &Name() { return Name_; }
 | 
					 | 
				
			||||||
        [[nodiscard]] std::string &ContentType() { return FileType_; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
						  private:
 | 
				
			||||||
        uint64_t        Length_ = 0;
 | 
							uint64_t Length_ = 0;
 | 
				
			||||||
        std::string     FileType_;
 | 
							std::string FileType_;
 | 
				
			||||||
        std::string     Name_;
 | 
							std::string Name_;
 | 
				
			||||||
        std::string     Id_;
 | 
							std::string Id_;
 | 
				
			||||||
        Poco::Logger    &Logger_;
 | 
							Poco::Logger &Logger_;
 | 
				
			||||||
        std::stringstream &OutputStream_;
 | 
							std::stringstream &OutputStream_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        inline Poco::Logger & Logger() { return Logger_; };
 | 
							inline Poco::Logger &Logger() { return Logger_; };
 | 
				
			||||||
    };
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class RESTAPI_avatar_handler : public RESTAPIHandler {
 | 
						class RESTAPI_avatar_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
                : RESTAPIHandler(bindings, L,
 | 
												   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                                 std::vector<std::string>{
 | 
												   bool Internal)
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_GET,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_POST,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
																		  Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
				
			||||||
                                         Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                         TransactionId,
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
                                         Internal) {}
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/avatar/{id}"}; };
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/avatar/{id}"}; };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoPost() final;
 | 
							void DoPost() final;
 | 
				
			||||||
        void DoDelete() final;
 | 
							void DoDelete() final;
 | 
				
			||||||
        void DoPut() final {};
 | 
							void DoPut() final{};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
    };
 | 
					} // namespace OpenWifi
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) {
 | 
						inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User,
 | 
				
			||||||
        U.currentPassword.clear();
 | 
											 SecurityObjects::UserInfo &U) {
 | 
				
			||||||
        U.lastPasswords.clear();
 | 
							U.currentPassword.clear();
 | 
				
			||||||
        U.oauthType.clear();
 | 
							U.lastPasswords.clear();
 | 
				
			||||||
    }
 | 
							U.oauthType.clear();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
						inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User,
 | 
				
			||||||
 | 
											 SecurityObjects::ApiKeyEntry &U) {
 | 
				
			||||||
 | 
							U.salt.clear();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -3,36 +3,29 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTAPI_email_handler.h"
 | 
					#include "RESTAPI_email_handler.h"
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Poco/Exception.h"
 | 
					 | 
				
			||||||
#include "Poco/JSON/Parser.h"
 | 
					#include "Poco/JSON/Parser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "SMTPMailerService.h"
 | 
					#include "SMTPMailerService.h"
 | 
				
			||||||
#include "framework/ow_constants.h"
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    void RESTAPI_email_handler::DoPost() {
 | 
						void RESTAPI_email_handler::DoPost() {
 | 
				
			||||||
        const auto & Obj = ParsedBody_;
 | 
							const auto &Obj = ParsedBody_;
 | 
				
			||||||
        if (Obj->has("subject") &&
 | 
							if (Obj->has("subject") && Obj->has("from") && Obj->has("text") && Obj->has("recipients") &&
 | 
				
			||||||
            Obj->has("from") &&
 | 
								Obj->isArray("recipients")) {
 | 
				
			||||||
            Obj->has("text") &&
 | 
					 | 
				
			||||||
            Obj->has("recipients") &&
 | 
					 | 
				
			||||||
            Obj->isArray("recipients")) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Poco::JSON::Array::Ptr Recipients = Obj->getArray("recipients");
 | 
								Poco::JSON::Array::Ptr Recipients = Obj->getArray("recipients");
 | 
				
			||||||
            auto Recipient = Recipients->get(0).toString();
 | 
								auto Recipient = Recipients->get(0).toString();
 | 
				
			||||||
            MessageAttributes Attrs;
 | 
								MessageAttributes Attrs;
 | 
				
			||||||
            Attrs[RECIPIENT_EMAIL] = Recipient;
 | 
								Attrs[RECIPIENT_EMAIL] = Recipient;
 | 
				
			||||||
            Attrs[SUBJECT] = Obj->get("subject").toString();
 | 
								Attrs[SUBJECT] = Obj->get("subject").toString();
 | 
				
			||||||
            Attrs[TEXT] = Obj->get("text").toString();
 | 
								Attrs[TEXT] = Obj->get("text").toString();
 | 
				
			||||||
            Attrs[SENDER] = Obj->get("from").toString();
 | 
								Attrs[SENDER] = Obj->get("from").toString();
 | 
				
			||||||
            if(SMTPMailerService()->SendMessage(Recipient, "password_reset.txt", Attrs)) {
 | 
								if (SMTPMailerService()->SendMessage(Recipient, "password_reset.txt", Attrs, false)) {
 | 
				
			||||||
                return OK();
 | 
									return OK();
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
            return ReturnStatus(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE);
 | 
								return ReturnStatus(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
							BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,22 +4,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_email_handler : public RESTAPIHandler {
 | 
						class RESTAPI_email_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
        : RESTAPIHandler(bindings, L,
 | 
												  RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                         std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
												  bool Internal)
 | 
				
			||||||
                                                  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                                  Server,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                                                  TransactionId,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                                  Internal) {}
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/email"};}
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/email"}; }
 | 
				
			||||||
        void DoGet() final {};
 | 
							void DoGet() final{};
 | 
				
			||||||
        void DoPost() final;
 | 
							void DoPost() final;
 | 
				
			||||||
        void DoDelete() final {};
 | 
							void DoDelete() final{};
 | 
				
			||||||
        void DoPut() final {};
 | 
							void DoPut() final{};
 | 
				
			||||||
    };
 | 
						};
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,170 +9,176 @@
 | 
				
			|||||||
#include "Poco/JSON/Parser.h"
 | 
					#include "Poco/JSON/Parser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "AuthService.h"
 | 
					#include "AuthService.h"
 | 
				
			||||||
#include "RESTAPI_oauth2_handler.h"
 | 
					 | 
				
			||||||
#include "MFAServer.h"
 | 
					#include "MFAServer.h"
 | 
				
			||||||
#include "framework/ow_constants.h"
 | 
					 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "RESTAPI_db_helpers.h"
 | 
					#include "RESTAPI_db_helpers.h"
 | 
				
			||||||
 | 
					#include "RESTAPI_oauth2_handler.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "framework/MicroService.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_oauth2_handler::DoGet() {
 | 
						void RESTAPI_oauth2_handler::DoGet() {
 | 
				
			||||||
        bool Expired = false, Contacted = false;
 | 
							bool Expired = false, Contacted = false;
 | 
				
			||||||
        if (!IsAuthorized(Expired, Contacted)) {
 | 
							if (!IsAuthorized(Expired, Contacted)) {
 | 
				
			||||||
            if (Expired)
 | 
								if (Expired)
 | 
				
			||||||
                return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
 | 
									return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
 | 
								return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        if (GetBoolParameter(RESTAPI::Protocol::ME)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::ME)) {
 | 
				
			||||||
            Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(),
 | 
								Logger_.information(fmt::format("REQUEST-ME({}): Request for {}",
 | 
				
			||||||
                                            UserInfo_.userinfo.email));
 | 
																Request->clientAddress().toString(),
 | 
				
			||||||
            Poco::JSON::Object Me;
 | 
																UserInfo_.userinfo.email));
 | 
				
			||||||
            SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
 | 
								Poco::JSON::Object Me;
 | 
				
			||||||
            Sanitize(UserInfo_, ReturnedUser);
 | 
								SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
 | 
				
			||||||
            ReturnedUser.to_json(Me);
 | 
								Sanitize(UserInfo_, ReturnedUser);
 | 
				
			||||||
            return ReturnObject(Me);
 | 
								ReturnedUser.to_json(Me);
 | 
				
			||||||
        }
 | 
								return ReturnObject(Me);
 | 
				
			||||||
        BadRequest(RESTAPI::Errors::UnrecognizedRequest);
 | 
							}
 | 
				
			||||||
    }
 | 
							BadRequest(RESTAPI::Errors::UnrecognizedRequest);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_oauth2_handler::DoDelete() {
 | 
						void RESTAPI_oauth2_handler::DoDelete() {
 | 
				
			||||||
        auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
 | 
							auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
 | 
				
			||||||
        std::string SessionToken;
 | 
							std::string SessionToken;
 | 
				
			||||||
        try {
 | 
							try {
 | 
				
			||||||
            Poco::Net::OAuth20Credentials Auth(*Request);
 | 
								Poco::Net::OAuth20Credentials Auth(*Request);
 | 
				
			||||||
            if (Auth.getScheme() == "Bearer") {
 | 
								if (Auth.getScheme() == "Bearer") {
 | 
				
			||||||
                SessionToken = Auth.getBearerToken();
 | 
									SessionToken = Auth.getBearerToken();
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        } catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        if (Token.empty() || (Token != SessionToken)) {
 | 
							if (Token.empty() || (Token != SessionToken)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        AuthService()->Logout(Token);
 | 
							AuthService()->Logout(Token);
 | 
				
			||||||
        return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
 | 
							return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void RESTAPI_oauth2_handler::DoPost() {
 | 
						void RESTAPI_oauth2_handler::DoPost() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const auto & Obj = ParsedBody_;
 | 
							const auto &Obj = ParsedBody_;
 | 
				
			||||||
        if(Obj == nullptr) {
 | 
							if (Obj == nullptr) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
								return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
 | 
							auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
 | 
				
			||||||
        auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
 | 
							auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
 | 
				
			||||||
        auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
 | 
							auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
 | 
				
			||||||
        auto refreshToken = GetS("refreshToken", Obj);
 | 
							auto refreshToken = GetS("refreshToken", Obj);
 | 
				
			||||||
        auto grant_type = GetParameter("grant_type");
 | 
							auto grant_type = GetParameter("grant_type");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::toLowerInPlace(userId);
 | 
							Poco::toLowerInPlace(userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!refreshToken.empty() && grant_type == "refresh_token") {
 | 
							if (!refreshToken.empty() && grant_type == "refresh_token") {
 | 
				
			||||||
            SecurityObjects::UserInfoAndPolicy UInfo;
 | 
								SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
            if(AuthService()->RefreshUserToken(*Request, refreshToken, UInfo)) {
 | 
								if (AuthService()->RefreshUserToken(*Request, refreshToken, UInfo)) {
 | 
				
			||||||
                Poco::JSON::Object  Answer;
 | 
									Poco::JSON::Object Answer;
 | 
				
			||||||
                UInfo.webtoken.to_json(Answer);
 | 
									UInfo.webtoken.to_json(Answer);
 | 
				
			||||||
                return ReturnObject(Answer);
 | 
									return ReturnObject(Answer);
 | 
				
			||||||
            } else {
 | 
								} else {
 | 
				
			||||||
                return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
 | 
									return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
 | 
				
			||||||
            Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
 | 
								Logger_.information(
 | 
				
			||||||
            Poco::JSON::Object  Answer;
 | 
									fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression());
 | 
								Poco::JSON::Object Answer;
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy());
 | 
								Answer.set(RESTAPI::Protocol::PASSWORDPATTERN,
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy());
 | 
										   AuthService()->PasswordValidationExpression());
 | 
				
			||||||
            return ReturnObject(Answer);
 | 
								Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy());
 | 
				
			||||||
        }
 | 
								Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy());
 | 
				
			||||||
 | 
								return ReturnObject(Answer);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
 | 
				
			||||||
            SecurityObjects::UserInfo UInfo1;
 | 
								SecurityObjects::UserInfo UInfo1;
 | 
				
			||||||
            auto UserExists = StorageService()->UserDB().GetUserByEmail(userId,UInfo1);
 | 
								auto UserExists = StorageService()->UserDB().GetUserByEmail(userId, UInfo1);
 | 
				
			||||||
            if(UserExists) {
 | 
								if (UserExists) {
 | 
				
			||||||
                Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId));
 | 
									Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}",
 | 
				
			||||||
                SecurityObjects::ActionLink NewLink;
 | 
																	Request->clientAddress().toString(), userId));
 | 
				
			||||||
 | 
									SecurityObjects::ActionLink NewLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
 | 
									NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
 | 
				
			||||||
                NewLink.id = MicroService::CreateUUID();
 | 
									NewLink.id = MicroService::CreateUUID();
 | 
				
			||||||
                NewLink.userId = UInfo1.id;
 | 
									NewLink.userId = UInfo1.id;
 | 
				
			||||||
                NewLink.created = OpenWifi::Now();
 | 
									NewLink.created = OpenWifi::Now();
 | 
				
			||||||
                NewLink.expires = NewLink.created + (24*60*60);
 | 
									NewLink.expires = NewLink.created + (24 * 60 * 60);
 | 
				
			||||||
                NewLink.userAction = true;
 | 
									NewLink.userAction = true;
 | 
				
			||||||
                StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
									StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Poco::JSON::Object ReturnObj;
 | 
									Poco::JSON::Object ReturnObj;
 | 
				
			||||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
									SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
                UInfo.webtoken.userMustChangePassword = true;
 | 
									UInfo.webtoken.userMustChangePassword = true;
 | 
				
			||||||
                UInfo.webtoken.to_json(ReturnObj);
 | 
									UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
                return ReturnObject(ReturnObj);
 | 
									return ReturnObject(ReturnObj);
 | 
				
			||||||
            } else {
 | 
								} else {
 | 
				
			||||||
                Poco::JSON::Object ReturnObj;
 | 
									Poco::JSON::Object ReturnObj;
 | 
				
			||||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
									SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
                UInfo.webtoken.userMustChangePassword = true;
 | 
									UInfo.webtoken.userMustChangePassword = true;
 | 
				
			||||||
                UInfo.webtoken.to_json(ReturnObj);
 | 
									UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
                return ReturnObject(ReturnObj);
 | 
									return ReturnObject(ReturnObj);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
 | 
				
			||||||
            Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId));
 | 
								Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}",
 | 
				
			||||||
            if(Obj->has("uuid")) {
 | 
																Request->clientAddress().toString(), userId));
 | 
				
			||||||
                auto uuid = Obj->get("uuid").toString();
 | 
								if (Obj->has("uuid")) {
 | 
				
			||||||
                if(MFAServer()->ResendCode(uuid))
 | 
									auto uuid = Obj->get("uuid").toString();
 | 
				
			||||||
                    return OK();
 | 
									if (MFAServer()->ResendCode(uuid))
 | 
				
			||||||
            }
 | 
										return OK();
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
 | 
								}
 | 
				
			||||||
        }
 | 
								return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE, false)) {
 | 
				
			||||||
            Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId));
 | 
								Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}",
 | 
				
			||||||
            if(Obj->has("uuid")) {
 | 
																Request->clientAddress().toString(), userId));
 | 
				
			||||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
								if (Obj->has("uuid")) {
 | 
				
			||||||
                if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) {
 | 
									SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
                    Poco::JSON::Object ReturnObj;
 | 
									if (MFAServer()->CompleteMFAChallenge(Obj, UInfo)) {
 | 
				
			||||||
                    UInfo.webtoken.to_json(ReturnObj);
 | 
										Poco::JSON::Object ReturnObj;
 | 
				
			||||||
                    return ReturnObject(ReturnObj);
 | 
										UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
                }
 | 
										return ReturnObject(ReturnObj);
 | 
				
			||||||
            }
 | 
									}
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
 | 
								}
 | 
				
			||||||
        }
 | 
								return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfoAndPolicy UInfo;
 | 
							SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
        bool Expired=false;
 | 
							bool Expired = false;
 | 
				
			||||||
        auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
 | 
							auto Code = AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
 | 
				
			||||||
        if (Code==SUCCESS) {
 | 
							switch (Code) {
 | 
				
			||||||
            Poco::JSON::Object ReturnObj;
 | 
							case SUCCESS: {
 | 
				
			||||||
            if(AuthService()->RequiresMFA(UInfo)) {
 | 
								Poco::JSON::Object ReturnObj;
 | 
				
			||||||
                if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
 | 
								if (AuthService()->RequiresMFA(UInfo)) {
 | 
				
			||||||
                    return ReturnObject(ReturnObj);
 | 
									if (MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
 | 
				
			||||||
                }
 | 
										return ReturnObject(ReturnObj);
 | 
				
			||||||
                Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
									}
 | 
				
			||||||
            }
 | 
									Logger_.warning(
 | 
				
			||||||
            UInfo.webtoken.to_json(ReturnObj);
 | 
										"MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
				
			||||||
            return ReturnObject(ReturnObj);
 | 
								}
 | 
				
			||||||
        } else {
 | 
								UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
 | 
								return ReturnObject(ReturnObj);
 | 
				
			||||||
            switch(Code) {
 | 
							}
 | 
				
			||||||
                case INVALID_CREDENTIALS:
 | 
							case INVALID_CREDENTIALS:
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
								return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
				
			||||||
                case PASSWORD_INVALID:
 | 
							case PASSWORD_INVALID:
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
 | 
								return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
 | 
				
			||||||
                case PASSWORD_ALREADY_USED:
 | 
							case PASSWORD_ALREADY_USED:
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
 | 
								return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
 | 
				
			||||||
                case USERNAME_PENDING_VERIFICATION:
 | 
							case USERNAME_PENDING_VERIFICATION:
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
 | 
								return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
 | 
				
			||||||
                case PASSWORD_CHANGE_REQUIRED:
 | 
							case PASSWORD_CHANGE_REQUIRED:
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
 | 
								return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
 | 
				
			||||||
                default:
 | 
							case ACCOUNT_SUSPENDED:
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
								return UnAuthorized(RESTAPI::Errors::ACCOUNT_SUSPENDED);
 | 
				
			||||||
            }
 | 
							default:
 | 
				
			||||||
            return;
 | 
								return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -7,26 +7,27 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
	class RESTAPI_oauth2_handler : public RESTAPIHandler {
 | 
						class RESTAPI_oauth2_handler : public RESTAPIHandler {
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
	    RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
 | 
												   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
 | 
												   bool Internal)
 | 
				
			||||||
			: RESTAPIHandler(bindings, L,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
													  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
																		  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
				
			||||||
                                                      Poco::Net::HTTPRequest::HTTP_GET,
 | 
																		  Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
													  Server,
 | 
												 Server, TransactionId, Internal, false, true,
 | 
				
			||||||
                                                      TransactionId,
 | 
												 RateLimit{.Interval = 1000, .MaxCalls = 10}) {}
 | 
				
			||||||
													  Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {}
 | 
							static auto PathName() {
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
 | 
								return std::list<std::string>{"/api/v1/oauth2/{token}", "/api/v1/oauth2"};
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
		void DoGet() final;
 | 
							void DoGet() final;
 | 
				
			||||||
		void DoPost() final;
 | 
							void DoPost() final;
 | 
				
			||||||
		void DoDelete() final;
 | 
							void DoDelete() final;
 | 
				
			||||||
		void DoPut() final {};
 | 
							void DoPut() final{};
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,30 +7,30 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_preferences::DoGet() {
 | 
						void RESTAPI_preferences::DoGet() {
 | 
				
			||||||
        SecurityObjects::Preferences    P;
 | 
							SecurityObjects::Preferences P;
 | 
				
			||||||
        Poco::JSON::Object  Answer;
 | 
							Poco::JSON::Object Answer;
 | 
				
			||||||
        StorageService()->PreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
 | 
							StorageService()->PreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
 | 
				
			||||||
        P.to_json(Answer);
 | 
							P.to_json(Answer);
 | 
				
			||||||
        ReturnObject(Answer);
 | 
							ReturnObject(Answer);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_preferences::DoPut() {
 | 
						void RESTAPI_preferences::DoPut() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::Preferences    P;
 | 
							SecurityObjects::Preferences P;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const auto & RawObject = ParsedBody_;
 | 
							const auto &RawObject = ParsedBody_;
 | 
				
			||||||
        if(!P.from_json(RawObject)) {
 | 
							if (!P.from_json(RawObject)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
								return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        P.id = UserInfo_.userinfo.id;
 | 
							P.id = UserInfo_.userinfo.id;
 | 
				
			||||||
        P.modified = OpenWifi::Now();
 | 
							P.modified = OpenWifi::Now();
 | 
				
			||||||
        StorageService()->PreferencesDB().SetPreferences(P);
 | 
							StorageService()->PreferencesDB().SetPreferences(P);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::JSON::Object  Answer;
 | 
							Poco::JSON::Object Answer;
 | 
				
			||||||
        P.to_json(Answer);
 | 
							P.to_json(Answer);
 | 
				
			||||||
        ReturnObject(Answer);
 | 
							ReturnObject(Answer);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,24 +4,23 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_preferences : public RESTAPIHandler {
 | 
						class RESTAPI_preferences : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
        : RESTAPIHandler(bindings, L,
 | 
												RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                         std::vector<std::string>{
 | 
												bool Internal)
 | 
				
			||||||
            Poco::Net::HTTPRequest::HTTP_GET,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
            Poco::Net::HTTPRequest::HTTP_PUT,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
            Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
				
			||||||
            Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
            TransactionId,
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
            Internal) {}
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; };
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; };
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoPut() final;
 | 
				
			||||||
        void DoPut() final;
 | 
							void DoPost() final{};
 | 
				
			||||||
        void DoPost() final {};
 | 
							void DoDelete() final{};
 | 
				
			||||||
        void DoDelete() final {};
 | 
						};
 | 
				
			||||||
    };
 | 
					} // namespace OpenWifi
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,88 +1,67 @@
 | 
				
			|||||||
//
 | 
					 //
 | 
				
			||||||
// Created by stephane bourque on 2021-10-23.
 | 
					// Created by stephane bourque on 2021-10-23.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "RESTAPI/RESTAPI_oauth2_handler.h"
 | 
					 | 
				
			||||||
#include "RESTAPI/RESTAPI_user_handler.h"
 | 
					 | 
				
			||||||
#include "RESTAPI/RESTAPI_users_handler.h"
 | 
					 | 
				
			||||||
#include "RESTAPI/RESTAPI_action_links.h"
 | 
					#include "RESTAPI/RESTAPI_action_links.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_system_endpoints_handler.h"
 | 
					#include "RESTAPI/RESTAPI_apiKey_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_asset_server.h"
 | 
					#include "RESTAPI/RESTAPI_asset_server.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_avatar_handler.h"
 | 
					#include "RESTAPI/RESTAPI_avatar_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_subavatar_handler.h"
 | 
					 | 
				
			||||||
#include "RESTAPI/RESTAPI_email_handler.h"
 | 
					#include "RESTAPI/RESTAPI_email_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_sms_handler.h"
 | 
					#include "RESTAPI/RESTAPI_oauth2_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_validate_token_handler.h"
 | 
					 | 
				
			||||||
#include "RESTAPI/RESTAPI_preferences.h"
 | 
					#include "RESTAPI/RESTAPI_preferences.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_subpreferences.h"
 | 
					#include "RESTAPI/RESTAPI_signup_handler.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_sms_handler.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_subavatar_handler.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_submfa_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_suboauth2_handler.h"
 | 
					#include "RESTAPI/RESTAPI_suboauth2_handler.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_subpreferences.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_subtotp_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_subuser_handler.h"
 | 
					#include "RESTAPI/RESTAPI_subuser_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_subusers_handler.h"
 | 
					#include "RESTAPI/RESTAPI_subusers_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
 | 
					#include "RESTAPI/RESTAPI_system_endpoints_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_submfa_handler.h"
 | 
					 | 
				
			||||||
#include "RESTAPI/RESTAPI_totp_handler.h"
 | 
					#include "RESTAPI/RESTAPI_totp_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_subtotp_handler.h"
 | 
					#include "RESTAPI/RESTAPI_user_handler.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_signup_handler.h"
 | 
					#include "RESTAPI/RESTAPI_users_handler.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_validate_apikey.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_validate_token_handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "RESTAPI_systemSecret_handler.h"
 | 
				
			||||||
 | 
					#include "framework/RESTAPI_SystemCommand.h"
 | 
				
			||||||
 | 
					#include "framework/RESTAPI_WebSocketServer.h"
 | 
				
			||||||
 | 
					#include "framework/RESTAPI_SystemConfiguration.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
 | 
						Poco::Net::HTTPRequestHandler *
 | 
				
			||||||
                                                            Poco::Logger & L, RESTAPI_GenericServer & S,
 | 
						RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
 | 
				
			||||||
                                                            uint64_t TransactionId) {
 | 
										  Poco::Logger &L, RESTAPI_GenericServerAccounting &S, uint64_t TransactionId) {
 | 
				
			||||||
        return RESTAPI_Router<
 | 
							return RESTAPI_Router<
 | 
				
			||||||
            RESTAPI_oauth2_handler,
 | 
								RESTAPI_oauth2_handler, RESTAPI_user_handler, RESTAPI_users_handler,
 | 
				
			||||||
            RESTAPI_user_handler,
 | 
								RESTAPI_system_command, RESTAPI_system_configuration, RESTAPI_asset_server, RESTAPI_system_endpoints_handler,
 | 
				
			||||||
            RESTAPI_users_handler,
 | 
								RESTAPI_action_links, RESTAPI_avatar_handler, RESTAPI_subavatar_handler,
 | 
				
			||||||
            RESTAPI_system_command,
 | 
								RESTAPI_email_handler, RESTAPI_sms_handler, RESTAPI_preferences, RESTAPI_subpreferences,
 | 
				
			||||||
            RESTAPI_asset_server,
 | 
								RESTAPI_suboauth2_handler, RESTAPI_subuser_handler, RESTAPI_subusers_handler,
 | 
				
			||||||
            RESTAPI_system_endpoints_handler,
 | 
								RESTAPI_submfa_handler, RESTAPI_totp_handler, RESTAPI_subtotp_handler,
 | 
				
			||||||
            RESTAPI_action_links,
 | 
								RESTAPI_signup_handler, RESTAPI_validate_sub_token_handler,
 | 
				
			||||||
            RESTAPI_avatar_handler,
 | 
								RESTAPI_validate_token_handler, RESTAPI_validate_apikey, RESTAPI_webSocketServer,
 | 
				
			||||||
            RESTAPI_subavatar_handler,
 | 
								RESTAPI_apiKey_handler, RESTAPI_systemSecret_handler>(Path, Bindings, L, S,
 | 
				
			||||||
            RESTAPI_email_handler,
 | 
																					  TransactionId);
 | 
				
			||||||
            RESTAPI_sms_handler,
 | 
						}
 | 
				
			||||||
            RESTAPI_preferences,
 | 
					 | 
				
			||||||
            RESTAPI_subpreferences,
 | 
					 | 
				
			||||||
            RESTAPI_suboauth2_handler,
 | 
					 | 
				
			||||||
            RESTAPI_subuser_handler,
 | 
					 | 
				
			||||||
            RESTAPI_subusers_handler,
 | 
					 | 
				
			||||||
            RESTAPI_submfa_handler,
 | 
					 | 
				
			||||||
            RESTAPI_totp_handler,
 | 
					 | 
				
			||||||
            RESTAPI_subtotp_handler,
 | 
					 | 
				
			||||||
            RESTAPI_signup_handler,
 | 
					 | 
				
			||||||
            RESTAPI_validate_sub_token_handler,
 | 
					 | 
				
			||||||
            RESTAPI_validate_token_handler
 | 
					 | 
				
			||||||
        >(Path, Bindings, L, S,TransactionId);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
 | 
						Poco::Net::HTTPRequestHandler *
 | 
				
			||||||
                                                            Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
 | 
						RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
 | 
				
			||||||
 | 
										  Poco::Logger &L, RESTAPI_GenericServerAccounting &S, uint64_t TransactionId) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return RESTAPI_Router_I<
 | 
							return RESTAPI_Router_I<
 | 
				
			||||||
            RESTAPI_oauth2_handler,
 | 
								RESTAPI_oauth2_handler, RESTAPI_user_handler, RESTAPI_users_handler,
 | 
				
			||||||
            RESTAPI_user_handler,
 | 
								RESTAPI_system_command, RESTAPI_system_configuration, RESTAPI_asset_server, RESTAPI_system_endpoints_handler,
 | 
				
			||||||
            RESTAPI_users_handler,
 | 
								RESTAPI_action_links, RESTAPI_avatar_handler, RESTAPI_subavatar_handler,
 | 
				
			||||||
            RESTAPI_system_command,
 | 
								RESTAPI_email_handler, RESTAPI_sms_handler, RESTAPI_preferences, RESTAPI_subpreferences,
 | 
				
			||||||
            RESTAPI_asset_server,
 | 
								RESTAPI_suboauth2_handler, RESTAPI_subuser_handler, RESTAPI_subusers_handler,
 | 
				
			||||||
            RESTAPI_system_endpoints_handler,
 | 
								RESTAPI_submfa_handler, RESTAPI_totp_handler, RESTAPI_subtotp_handler,
 | 
				
			||||||
            RESTAPI_action_links,
 | 
								RESTAPI_validate_sub_token_handler, RESTAPI_validate_token_handler,
 | 
				
			||||||
            RESTAPI_avatar_handler,
 | 
								RESTAPI_validate_apikey, RESTAPI_signup_handler, RESTAPI_systemSecret_handler>(
 | 
				
			||||||
            RESTAPI_subavatar_handler,
 | 
								Path, Bindings, L, S, TransactionId);
 | 
				
			||||||
            RESTAPI_email_handler,
 | 
						}
 | 
				
			||||||
            RESTAPI_sms_handler,
 | 
					} // namespace OpenWifi
 | 
				
			||||||
            RESTAPI_preferences,
 | 
					 | 
				
			||||||
            RESTAPI_subpreferences,
 | 
					 | 
				
			||||||
            RESTAPI_suboauth2_handler,
 | 
					 | 
				
			||||||
            RESTAPI_subuser_handler,
 | 
					 | 
				
			||||||
            RESTAPI_subusers_handler,
 | 
					 | 
				
			||||||
            RESTAPI_submfa_handler,
 | 
					 | 
				
			||||||
            RESTAPI_totp_handler,
 | 
					 | 
				
			||||||
            RESTAPI_subtotp_handler,
 | 
					 | 
				
			||||||
            RESTAPI_validate_sub_token_handler,
 | 
					 | 
				
			||||||
            RESTAPI_validate_token_handler,
 | 
					 | 
				
			||||||
            RESTAPI_signup_handler
 | 
					 | 
				
			||||||
        >(Path, Bindings, L, S, TransactionId);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -3,72 +3,74 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTAPI_signup_handler.h"
 | 
					#include "RESTAPI_signup_handler.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
					#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define __DBG__ std::cout << __LINE__ << std::endl;
 | 
					#define __DBG__ std::cout << __LINE__ << std::endl;
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_signup_handler::DoPost() {
 | 
						void RESTAPI_signup_handler::DoPost() {
 | 
				
			||||||
        auto UserName = GetParameter("email");
 | 
							auto UserName = GetParameter("email");
 | 
				
			||||||
        auto signupUUID = GetParameter("signupUUID");
 | 
							auto signupUUID = GetParameter("signupUUID");
 | 
				
			||||||
        auto owner = GetParameter("owner");
 | 
							auto owner = GetParameter("owner");
 | 
				
			||||||
        auto operatorName = GetParameter("operatorName");
 | 
							auto operatorName = GetParameter("operatorName");
 | 
				
			||||||
        if(UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) {
 | 
							if (UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) {
 | 
				
			||||||
            Logger().error("Signup requires: email, signupUUID, operatorName, and owner.");
 | 
								Logger().error("Signup requires: email, signupUUID, operatorName, and owner.");
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!Utils::ValidEMailAddress(UserName)) {
 | 
							if (!Utils::ValidEMailAddress(UserName)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
 | 
								return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Do we already exist? Can only signup once...
 | 
							// Do we already exist? Can only signup once...
 | 
				
			||||||
        SecurityObjects::UserInfo   Existing;
 | 
							SecurityObjects::UserInfo Existing;
 | 
				
			||||||
        if(StorageService()->SubDB().GetUserByEmail(UserName,Existing)) {
 | 
							if (StorageService()->SubDB().GetUserByEmail(UserName, Existing)) {
 | 
				
			||||||
            if(Existing.signingUp.empty()) {
 | 
								if (Existing.signingUp.empty()) {
 | 
				
			||||||
                return BadRequest(RESTAPI::Errors::SignupAlreadySigned);
 | 
									return BadRequest(RESTAPI::Errors::SignupAlreadySigned);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(Existing.waitingForEmailCheck) {
 | 
								if (Existing.waitingForEmailCheck) {
 | 
				
			||||||
                return BadRequest(RESTAPI::Errors::SignupEmailCheck);
 | 
									return BadRequest(RESTAPI::Errors::SignupEmailCheck);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::SignupWaitingForDevice);
 | 
								return BadRequest(RESTAPI::Errors::SignupWaitingForDevice);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfo   NewSub;
 | 
							SecurityObjects::UserInfo NewSub;
 | 
				
			||||||
        NewSub.signingUp = operatorName + ":" + signupUUID;
 | 
							NewSub.signingUp = operatorName + ":" + signupUUID;
 | 
				
			||||||
        NewSub.waitingForEmailCheck = true;
 | 
							NewSub.waitingForEmailCheck = true;
 | 
				
			||||||
        NewSub.name = UserName;
 | 
							NewSub.name = UserName;
 | 
				
			||||||
        NewSub.modified = OpenWifi::Now();
 | 
							NewSub.modified = OpenWifi::Now();
 | 
				
			||||||
        NewSub.creationDate = OpenWifi::Now();
 | 
							NewSub.creationDate = OpenWifi::Now();
 | 
				
			||||||
        NewSub.id = MicroService::instance().CreateUUID();
 | 
							NewSub.id = MicroServiceCreateUUID();
 | 
				
			||||||
        NewSub.email = UserName;
 | 
							NewSub.email = UserName;
 | 
				
			||||||
        NewSub.userRole = SecurityObjects::SUBSCRIBER;
 | 
							NewSub.userRole = SecurityObjects::SUBSCRIBER;
 | 
				
			||||||
        NewSub.changePassword = true;
 | 
							NewSub.changePassword = true;
 | 
				
			||||||
        NewSub.owner = owner;
 | 
							NewSub.owner = owner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        StorageService()->SubDB().CreateRecord(NewSub);
 | 
							StorageService()->SubDB().CreateRecord(NewSub);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}", Request->clientAddress().toString(), UserName));
 | 
							Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}",
 | 
				
			||||||
        SecurityObjects::ActionLink NewLink;
 | 
															Request->clientAddress().toString(), UserName));
 | 
				
			||||||
 | 
							SecurityObjects::ActionLink NewLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP;
 | 
							NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP;
 | 
				
			||||||
        NewLink.id = MicroService::CreateUUID();
 | 
							NewLink.id = MicroServiceCreateUUID();
 | 
				
			||||||
        NewLink.userId = NewSub.id;
 | 
							NewLink.userId = NewSub.id;
 | 
				
			||||||
        NewLink.created = OpenWifi::Now();
 | 
							NewLink.created = OpenWifi::Now();
 | 
				
			||||||
        NewLink.expires = NewLink.created + (1*60*60);  // 1 hour
 | 
							NewLink.expires = NewLink.created + (1 * 60 * 60); // 1 hour
 | 
				
			||||||
        NewLink.userAction = false;
 | 
							NewLink.userAction = false;
 | 
				
			||||||
        StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
							StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::JSON::Object  Answer;
 | 
							Poco::JSON::Object Answer;
 | 
				
			||||||
        NewSub.to_json(Answer);
 | 
							NewSub.to_json(Answer);
 | 
				
			||||||
        return ReturnObject(Answer);
 | 
							return ReturnObject(Answer);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_signup_handler::DoPut() {
 | 
						void RESTAPI_signup_handler::DoPut() {
 | 
				
			||||||
        // TODO
 | 
							// TODO
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,36 +4,35 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_signup_handler : public RESTAPIHandler {
 | 
						class RESTAPI_signup_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
                : RESTAPIHandler(bindings, L,
 | 
												   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                                 std::vector<std::string>{
 | 
												   bool Internal)
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_POST,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_OPTIONS,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_PUT},
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS,
 | 
				
			||||||
                                 Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_PUT},
 | 
				
			||||||
                                 TransactionId,
 | 
												 Server, TransactionId, Internal, false, true) {}
 | 
				
			||||||
                                 Internal, false, true ){}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/signup"}; };
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/signup"}; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*        inline bool RoleIsAuthorized(std::string & Reason) {
 | 
							/*        inline bool RoleIsAuthorized(std::string & Reason) {
 | 
				
			||||||
            if(UserInfo_.userinfo.userRole != SecurityObjects::USER_ROLE::SUBSCRIBER) {
 | 
										if(UserInfo_.userinfo.userRole != SecurityObjects::USER_ROLE::SUBSCRIBER) {
 | 
				
			||||||
                Reason = "User must be a subscriber";
 | 
											Reason = "User must be a subscriber";
 | 
				
			||||||
                return false;
 | 
											return false;
 | 
				
			||||||
            }
 | 
										}
 | 
				
			||||||
            return true;
 | 
										return true;
 | 
				
			||||||
        }
 | 
									}
 | 
				
			||||||
*/
 | 
							*/
 | 
				
			||||||
        void DoGet() final {};
 | 
							void DoGet() final{};
 | 
				
			||||||
        void DoPost() final;
 | 
							void DoPost() final;
 | 
				
			||||||
        void DoPut() final ;
 | 
							void DoPut() final;
 | 
				
			||||||
        void DoDelete() final {};
 | 
							void DoDelete() final{};
 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    };
 | 
						  private:
 | 
				
			||||||
}
 | 
						};
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,55 +5,53 @@
 | 
				
			|||||||
#include "RESTAPI_sms_handler.h"
 | 
					#include "RESTAPI_sms_handler.h"
 | 
				
			||||||
#include "SMSSender.h"
 | 
					#include "SMSSender.h"
 | 
				
			||||||
#include "framework/ow_constants.h"
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void OpenWifi::RESTAPI_sms_handler::DoPost() {
 | 
						void OpenWifi::RESTAPI_sms_handler::DoPost() {
 | 
				
			||||||
        const auto &Obj = ParsedBody_;
 | 
							const auto &Obj = ParsedBody_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!SMSSender()->Enabled()) {
 | 
							if (!SMSSender()->Enabled()) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
 | 
								return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string Arg;
 | 
							std::string Arg;
 | 
				
			||||||
        if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) {
 | 
							if (HasParameter("validateNumber", Arg) && Arg == "true" && Obj->has("to")) {
 | 
				
			||||||
            auto Number = Obj->get("to").toString();
 | 
								auto Number = Obj->get("to").toString();
 | 
				
			||||||
            if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) {
 | 
								if (SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) {
 | 
				
			||||||
                return OK();
 | 
									return OK();
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry);
 | 
								return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string Code;
 | 
							std::string Code;
 | 
				
			||||||
        if( HasParameter("completeValidation",Arg) &&
 | 
							if (HasParameter("completeValidation", Arg) && Arg == "true" &&
 | 
				
			||||||
            Arg=="true" &&
 | 
								HasParameter("validationCode", Code) && Obj->has("to")) {
 | 
				
			||||||
            HasParameter("validationCode", Code) &&
 | 
								auto Number = Obj->get("to").toString();
 | 
				
			||||||
            Obj->has("to")) {
 | 
								if (SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
 | 
				
			||||||
            auto Number = Obj->get("to").toString();
 | 
									return OK();
 | 
				
			||||||
            if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
 | 
								}
 | 
				
			||||||
                return OK();
 | 
								return BadRequest(RESTAPI::Errors::SMSCouldNotValidate);
 | 
				
			||||||
            }
 | 
							}
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::SMSCouldNotValidate);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT &&
 | 
					        if(Internal_) {
 | 
				
			||||||
            UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER &&
 | 
					            poco_information(Logger(),fmt::format("Internal SMS request: TID={}", TransactionId_));
 | 
				
			||||||
            UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
 | 
					        } else if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
								UserInfo_.userinfo.userRole != SecurityObjects::PARTNER &&
 | 
				
			||||||
        }
 | 
								UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
 | 
				
			||||||
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (Obj->has("to") &&
 | 
							if (Obj->has("to") && Obj->has("text")) {
 | 
				
			||||||
            Obj->has("text")) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            std::string PhoneNumber = Obj->get("to").toString();
 | 
								std::string PhoneNumber = Obj->get("to").toString();
 | 
				
			||||||
            std::string Text = Obj->get("text").toString();
 | 
								std::string Text = Obj->get("text").toString();
 | 
				
			||||||
            if(SMSSender()->Send(PhoneNumber, Text))
 | 
								if (SMSSender()->Send(PhoneNumber, Text))
 | 
				
			||||||
                return OK();
 | 
									return OK();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
 | 
								return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
							BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,22 +4,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_sms_handler : public RESTAPIHandler {
 | 
						class RESTAPI_sms_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
        : RESTAPIHandler(bindings, L,
 | 
												RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                         std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
												bool Internal)
 | 
				
			||||||
                                                  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                                  Server,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                                                  TransactionId,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                                  Internal) {}
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/sms"};}
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/sms"}; }
 | 
				
			||||||
        void DoGet() final {};
 | 
							void DoGet() final{};
 | 
				
			||||||
        void DoPost() final;
 | 
							void DoPost() final;
 | 
				
			||||||
        void DoDelete() final {};
 | 
							void DoDelete() final{};
 | 
				
			||||||
        void DoPut() final {};
 | 
							void DoPut() final{};
 | 
				
			||||||
    };
 | 
						};
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,77 +5,84 @@
 | 
				
			|||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Poco/CountingStream.h"
 | 
				
			||||||
 | 
					#include "Poco/Net/HTMLForm.h"
 | 
				
			||||||
#include "RESTAPI_subavatar_handler.h"
 | 
					#include "RESTAPI_subavatar_handler.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					#include "StorageService.h"
 | 
				
			||||||
#include "Poco/Net/HTMLForm.h"
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
 | 
						void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header,
 | 
				
			||||||
        FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
 | 
															  std::istream &Stream) {
 | 
				
			||||||
        if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
 | 
							FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
 | 
				
			||||||
            std::string Disposition;
 | 
							if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
 | 
				
			||||||
            Poco::Net::NameValueCollection Parameters;
 | 
								std::string Disposition;
 | 
				
			||||||
            Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
 | 
								Poco::Net::NameValueCollection Parameters;
 | 
				
			||||||
            Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
								Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION],
 | 
				
			||||||
        }
 | 
																		  Disposition, Parameters);
 | 
				
			||||||
        Poco::CountingInputStream InputStream(Stream);
 | 
								Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
				
			||||||
        Poco::StreamCopier::copyStream(InputStream, OutputStream_);
 | 
							}
 | 
				
			||||||
        Length_ = OutputStream_.str().size();
 | 
							Poco::CountingInputStream InputStream(Stream);
 | 
				
			||||||
    };
 | 
							Poco::StreamCopier::copyStream(InputStream, OutputStream_);
 | 
				
			||||||
 | 
							Length_ = OutputStream_.str().size();
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subavatar_handler::DoPost() {
 | 
						void RESTAPI_subavatar_handler::DoPost() {
 | 
				
			||||||
        std::string Id = UserInfo_.userinfo.id;
 | 
							std::string Id = UserInfo_.userinfo.id;
 | 
				
			||||||
        SecurityObjects::UserInfo UInfo;
 | 
							SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::stringstream SS;
 | 
							std::stringstream SS;
 | 
				
			||||||
        SubAvatarPartHandler partHandler(Id, Logger_, SS);
 | 
							SubAvatarPartHandler partHandler(Id, Logger_, SS);
 | 
				
			||||||
        Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
 | 
							Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
 | 
				
			||||||
        Poco::JSON::Object Answer;
 | 
							Poco::JSON::Object Answer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) {
 | 
							if (!partHandler.Name().empty() &&
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
								partHandler.Length() < MicroServiceConfigGetInt("openwifi.avatar.maxsize", 2000000)) {
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
 | 
								Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
				
			||||||
            Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType()));
 | 
								Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
 | 
				
			||||||
            StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email,
 | 
								Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(),
 | 
				
			||||||
                                 Id, SS.str(), partHandler.ContentType(), partHandler.Name());
 | 
																partHandler.ContentType()));
 | 
				
			||||||
            StorageService()->SubDB().SetAvatar(Id,"1");
 | 
								StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email, Id, SS.str(),
 | 
				
			||||||
            Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email));
 | 
																		  partHandler.ContentType(),
 | 
				
			||||||
        } else {
 | 
																		  partHandler.Name());
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
								StorageService()->SubDB().SetAvatar(Id, "1");
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
 | 
								Logger().information(fmt::format("Adding avatar for {}", UserInfo_.userinfo.email));
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
 | 
							} else {
 | 
				
			||||||
        }
 | 
								Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
				
			||||||
        ReturnObject(Answer);
 | 
								Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
 | 
				
			||||||
    }
 | 
								Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ReturnObject(Answer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subavatar_handler::DoGet() {
 | 
						void RESTAPI_subavatar_handler::DoGet() {
 | 
				
			||||||
        std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
							std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
				
			||||||
        if (Id.empty()) {
 | 
							if (Id.empty()) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string Type, Name, AvatarContent;
 | 
							std::string Type, Name, AvatarContent;
 | 
				
			||||||
        if (!StorageService()->SubAvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) {
 | 
							if (!StorageService()->SubAvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent,
 | 
				
			||||||
            return NotFound();
 | 
																		   Type, Name)) {
 | 
				
			||||||
        }
 | 
								return NotFound();
 | 
				
			||||||
        Logger().information(fmt::format("Retrieving avatar for {}",UserInfo_.userinfo.email));
 | 
							}
 | 
				
			||||||
        return SendFileContent(AvatarContent, Type, Name);
 | 
							Logger().information(fmt::format("Retrieving avatar for {}", UserInfo_.userinfo.email));
 | 
				
			||||||
    }
 | 
							return SendFileContent(AvatarContent, Type, Name);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subavatar_handler::DoDelete() {
 | 
						void RESTAPI_subavatar_handler::DoDelete() {
 | 
				
			||||||
        std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
							std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) {
 | 
							if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT && Id != UserInfo_.userinfo.id) {
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!StorageService()->SubAvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
 | 
							if (!StorageService()->SubAvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email));
 | 
							Logger().information(fmt::format("Deleted avatar for {}", UserInfo_.userinfo.email));
 | 
				
			||||||
        StorageService()->SubDB().SetAvatar(Id,"");
 | 
							StorageService()->SubDB().SetAvatar(Id, "");
 | 
				
			||||||
        OK();
 | 
							OK();
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,51 +3,47 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "Poco/Net/PartHandler.h"
 | 
				
			||||||
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class SubAvatarPartHandler : public Poco::Net::PartHandler {
 | 
						class SubAvatarPartHandler : public Poco::Net::PartHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
 | 
							SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream &ofs)
 | 
				
			||||||
                Id_(std::move(Id)),
 | 
								: Id_(std::move(Id)), Logger_(Logger), OutputStream_(ofs) {}
 | 
				
			||||||
                Logger_(Logger),
 | 
							void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
 | 
				
			||||||
                OutputStream_(ofs){
 | 
							[[nodiscard]] uint64_t Length() const { return Length_; }
 | 
				
			||||||
        }
 | 
							[[nodiscard]] std::string &Name() { return Name_; }
 | 
				
			||||||
        void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
 | 
							[[nodiscard]] std::string &ContentType() { return FileType_; }
 | 
				
			||||||
        [[nodiscard]] uint64_t Length() const { return Length_; }
 | 
					 | 
				
			||||||
        [[nodiscard]] std::string &Name() { return Name_; }
 | 
					 | 
				
			||||||
        [[nodiscard]] std::string &ContentType() { return FileType_; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
						  private:
 | 
				
			||||||
        uint64_t        Length_ = 0;
 | 
							uint64_t Length_ = 0;
 | 
				
			||||||
        std::string     FileType_;
 | 
							std::string FileType_;
 | 
				
			||||||
        std::string     Name_;
 | 
							std::string Name_;
 | 
				
			||||||
        std::string     Id_;
 | 
							std::string Id_;
 | 
				
			||||||
        Poco::Logger    &Logger_;
 | 
							Poco::Logger &Logger_;
 | 
				
			||||||
        std::stringstream &OutputStream_;
 | 
							std::stringstream &OutputStream_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        inline Poco::Logger & Logger() { return Logger_; }
 | 
							inline Poco::Logger &Logger() { return Logger_; }
 | 
				
			||||||
    };
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class RESTAPI_subavatar_handler : public RESTAPIHandler {
 | 
						class RESTAPI_subavatar_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
                : RESTAPIHandler(bindings, L,
 | 
													  RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                                 std::vector<std::string>{
 | 
													  bool Internal)
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_GET,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_POST,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
																		  Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                                         Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
				
			||||||
                                         Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                         TransactionId,
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
                                         Internal) {}
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; };
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoPost() final;
 | 
							void DoPost() final;
 | 
				
			||||||
        void DoDelete() final;
 | 
							void DoDelete() final;
 | 
				
			||||||
        void DoPut() final {};
 | 
							void DoPut() final{};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
    };
 | 
					} // namespace OpenWifi
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,135 +3,140 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTAPI_submfa_handler.h"
 | 
					#include "RESTAPI_submfa_handler.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "SMSSender.h"
 | 
					#include "SMSSender.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_submfa_handler::DoGet() {
 | 
						void RESTAPI_submfa_handler::DoGet() {
 | 
				
			||||||
        SecurityObjects::UserInfo   User;
 | 
							SecurityObjects::UserInfo User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id,User)) {
 | 
							if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User)) {
 | 
				
			||||||
            Poco::JSON::Object              Answer;
 | 
								Poco::JSON::Object Answer;
 | 
				
			||||||
            SecurityObjects::SubMfaConfig   MFC;
 | 
								SecurityObjects::SubMfaConfig MFC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            MFC.id = User.id;
 | 
								MFC.id = User.id;
 | 
				
			||||||
            if(User.userTypeProprietaryInfo.mfa.enabled) {
 | 
								if (User.userTypeProprietaryInfo.mfa.enabled) {
 | 
				
			||||||
                if(User.userTypeProprietaryInfo.mfa.method == "sms") {
 | 
									if (User.userTypeProprietaryInfo.mfa.method == "sms") {
 | 
				
			||||||
                    MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number;
 | 
										MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number;
 | 
				
			||||||
                    MFC.type = "sms";
 | 
										MFC.type = "sms";
 | 
				
			||||||
                } else if(User.userTypeProprietaryInfo.mfa.method == "email") {
 | 
									} else if (User.userTypeProprietaryInfo.mfa.method == "email") {
 | 
				
			||||||
                    MFC.email = User.email;
 | 
										MFC.email = User.email;
 | 
				
			||||||
                    MFC.type = "email";
 | 
										MFC.type = "email";
 | 
				
			||||||
                }
 | 
									}
 | 
				
			||||||
            } else {
 | 
								} else {
 | 
				
			||||||
                MFC.type = "disabled";
 | 
									MFC.type = "disabled";
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
            MFC.to_json(Answer);
 | 
								MFC.to_json(Answer);
 | 
				
			||||||
            return ReturnObject(Answer);
 | 
								return ReturnObject(Answer);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        NotFound();
 | 
							NotFound();
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_submfa_handler::DoPut() {
 | 
						void RESTAPI_submfa_handler::DoPut() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
							try {
 | 
				
			||||||
            const auto & Body = ParsedBody_;
 | 
								const auto &Body = ParsedBody_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SecurityObjects::SubMfaConfig MFC;
 | 
								SecurityObjects::SubMfaConfig MFC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!MFC.from_json(Body)) {
 | 
								if (!MFC.from_json(Body)) {
 | 
				
			||||||
                return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
									return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (MFC.type == "disabled") {
 | 
								if (MFC.type == "disabled") {
 | 
				
			||||||
                SecurityObjects::UserInfo User;
 | 
									SecurityObjects::UserInfo User;
 | 
				
			||||||
                StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
									StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
				
			||||||
                User.userTypeProprietaryInfo.mfa.enabled = false;
 | 
									User.userTypeProprietaryInfo.mfa.enabled = false;
 | 
				
			||||||
                StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
 | 
									StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,
 | 
				
			||||||
 | 
																			 UserInfo_.userinfo.id, User);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Poco::JSON::Object Answer;
 | 
									Poco::JSON::Object Answer;
 | 
				
			||||||
                MFC.to_json(Answer);
 | 
									MFC.to_json(Answer);
 | 
				
			||||||
                return ReturnObject(Answer);
 | 
									return ReturnObject(Answer);
 | 
				
			||||||
            } else if (MFC.type == "email") {
 | 
								} else if (MFC.type == "email") {
 | 
				
			||||||
                SecurityObjects::UserInfo User;
 | 
									SecurityObjects::UserInfo User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
									StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
				
			||||||
                User.userTypeProprietaryInfo.mfa.enabled = true;
 | 
									User.userTypeProprietaryInfo.mfa.enabled = true;
 | 
				
			||||||
                User.userTypeProprietaryInfo.mfa.method = "email";
 | 
									User.userTypeProprietaryInfo.mfa.method = "email";
 | 
				
			||||||
                StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
 | 
									StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,
 | 
				
			||||||
 | 
																			 UserInfo_.userinfo.id, User);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                MFC.sms = MFC.sms;
 | 
									MFC.sms = MFC.sms;
 | 
				
			||||||
                MFC.type = "email";
 | 
									MFC.type = "email";
 | 
				
			||||||
                MFC.email = UserInfo_.userinfo.email;
 | 
									MFC.email = UserInfo_.userinfo.email;
 | 
				
			||||||
                MFC.id = MicroService::instance().CreateUUID();
 | 
									MFC.id = MicroServiceCreateUUID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Poco::JSON::Object Answer;
 | 
									Poco::JSON::Object Answer;
 | 
				
			||||||
                MFC.to_json(Answer);
 | 
									MFC.to_json(Answer);
 | 
				
			||||||
                return ReturnObject(Answer);
 | 
									return ReturnObject(Answer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            } else if (MFC.type == "sms") {
 | 
								} else if (MFC.type == "sms") {
 | 
				
			||||||
                if (GetBoolParameter("startValidation", false)) {
 | 
									if (GetBoolParameter("startValidation", false)) {
 | 
				
			||||||
                    if (MFC.sms.empty()) {
 | 
										if (MFC.sms.empty()) {
 | 
				
			||||||
                        return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
 | 
											return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
 | 
				
			||||||
                    }
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if(!SMSSender()->Enabled()) {
 | 
										if (!SMSSender()->Enabled()) {
 | 
				
			||||||
                        return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
 | 
											return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
 | 
				
			||||||
                    }
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) {
 | 
										if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) {
 | 
				
			||||||
                        return OK();
 | 
											return OK();
 | 
				
			||||||
                    } else {
 | 
										} else {
 | 
				
			||||||
                        return InternalError(RESTAPI::Errors::SMSTryLater);
 | 
											return InternalError(RESTAPI::Errors::SMSTryLater);
 | 
				
			||||||
                    }
 | 
										}
 | 
				
			||||||
                } else if (GetBoolParameter("completeValidation", false)) {
 | 
									} else if (GetBoolParameter("completeValidation", false)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if(!SMSSender()->Enabled()) {
 | 
										if (!SMSSender()->Enabled()) {
 | 
				
			||||||
                        return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
 | 
											return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
 | 
				
			||||||
                    }
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    auto ChallengeCode = GetParameter("challengeCode", "");
 | 
										auto ChallengeCode = GetParameter("challengeCode", "");
 | 
				
			||||||
                    if (ChallengeCode.empty()) {
 | 
										if (ChallengeCode.empty()) {
 | 
				
			||||||
                        return BadRequest(RESTAPI::Errors::SMSMissingChallenge);
 | 
											return BadRequest(RESTAPI::Errors::SMSMissingChallenge);
 | 
				
			||||||
                    }
 | 
										}
 | 
				
			||||||
                    if (MFC.sms.empty()) {
 | 
										if (MFC.sms.empty()) {
 | 
				
			||||||
                        return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
 | 
											return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
 | 
				
			||||||
                    }
 | 
										}
 | 
				
			||||||
                    if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) {
 | 
										if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode,
 | 
				
			||||||
                        SecurityObjects::UserInfo User;
 | 
																			UserInfo_.userinfo.email)) {
 | 
				
			||||||
 | 
											SecurityObjects::UserInfo User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
											StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
				
			||||||
                        User.userTypeProprietaryInfo.mfa.enabled = true;
 | 
											User.userTypeProprietaryInfo.mfa.enabled = true;
 | 
				
			||||||
                        User.userTypeProprietaryInfo.mfa.method = "sms";
 | 
											User.userTypeProprietaryInfo.mfa.method = "sms";
 | 
				
			||||||
                        SecurityObjects::MobilePhoneNumber PhoneNumber;
 | 
											SecurityObjects::MobilePhoneNumber PhoneNumber;
 | 
				
			||||||
                        PhoneNumber.number = MFC.sms;
 | 
											PhoneNumber.number = MFC.sms;
 | 
				
			||||||
                        PhoneNumber.primary = true;
 | 
											PhoneNumber.primary = true;
 | 
				
			||||||
                        PhoneNumber.verified = true;
 | 
											PhoneNumber.verified = true;
 | 
				
			||||||
                        User.userTypeProprietaryInfo.mobiles.clear();
 | 
											User.userTypeProprietaryInfo.mobiles.clear();
 | 
				
			||||||
                        User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber);
 | 
											User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
 | 
											StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,
 | 
				
			||||||
 | 
																					 UserInfo_.userinfo.id, User);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        MFC.sms = MFC.sms;
 | 
											MFC.sms = MFC.sms;
 | 
				
			||||||
                        MFC.type = "sms";
 | 
											MFC.type = "sms";
 | 
				
			||||||
                        MFC.email = UserInfo_.userinfo.email;
 | 
											MFC.email = UserInfo_.userinfo.email;
 | 
				
			||||||
                        MFC.id = MicroService::instance().CreateUUID();
 | 
											MFC.id = MicroServiceCreateUUID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        Poco::JSON::Object Answer;
 | 
											Poco::JSON::Object Answer;
 | 
				
			||||||
                        MFC.to_json(Answer);
 | 
											MFC.to_json(Answer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        return ReturnObject(Answer);
 | 
											return ReturnObject(Answer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    } else {
 | 
										} else {
 | 
				
			||||||
                        return InternalError(RESTAPI::Errors::SMSTryLater);
 | 
											return InternalError(RESTAPI::Errors::SMSTryLater);
 | 
				
			||||||
                    }
 | 
										}
 | 
				
			||||||
                }
 | 
									}
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        } catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
            Logger_.log(E);
 | 
								Logger_.log(E);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
							return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,24 +4,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_submfa_handler : public RESTAPIHandler {
 | 
						class RESTAPI_submfa_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
        : RESTAPIHandler(bindings, L,
 | 
												   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                         std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
 | 
												   bool Internal)
 | 
				
			||||||
                                                  Poco::Net::HTTPRequest::HTTP_GET,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                                  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
 | 
				
			||||||
                                                  Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
                                                  TransactionId,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                                  Internal, true, false , RateLimit{.Interval=1000,.MaxCalls=10},
 | 
												 Server, TransactionId, Internal, true, false,
 | 
				
			||||||
                                                  true) {}
 | 
												 RateLimit{.Interval = 1000, .MaxCalls = 10}, true) {}
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; };
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; };
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoPost() final {};
 | 
							void DoPost() final{};
 | 
				
			||||||
        void DoDelete() final {};
 | 
							void DoDelete() final{};
 | 
				
			||||||
        void DoPut() final ;
 | 
							void DoPut() final;
 | 
				
			||||||
    };
 | 
						};
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,161 +5,167 @@
 | 
				
			|||||||
#include "RESTAPI_suboauth2_handler.h"
 | 
					#include "RESTAPI_suboauth2_handler.h"
 | 
				
			||||||
#include "AuthService.h"
 | 
					#include "AuthService.h"
 | 
				
			||||||
#include "MFAServer.h"
 | 
					#include "MFAServer.h"
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
					#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_suboauth2_handler::DoGet() {
 | 
						void RESTAPI_suboauth2_handler::DoGet() {
 | 
				
			||||||
        bool Expired = false, Contacted = false;
 | 
							bool Expired = false, Contacted = false;
 | 
				
			||||||
        if (!IsAuthorized(Expired, Contacted, true)) {
 | 
							if (!IsAuthorized(Expired, Contacted, true)) {
 | 
				
			||||||
            if(Expired)
 | 
								if (Expired)
 | 
				
			||||||
                return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
 | 
									return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
 | 
								return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
 | 
							bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
 | 
				
			||||||
        if(GetMe) {
 | 
							if (GetMe) {
 | 
				
			||||||
            Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(),
 | 
								Logger_.information(fmt::format("REQUEST-ME({}): Request for {}",
 | 
				
			||||||
                                             UserInfo_.userinfo.email));
 | 
																Request->clientAddress().toString(),
 | 
				
			||||||
            Poco::JSON::Object Me;
 | 
																UserInfo_.userinfo.email));
 | 
				
			||||||
            SecurityObjects::UserInfo   ReturnedUser = UserInfo_.userinfo;
 | 
								Poco::JSON::Object Me;
 | 
				
			||||||
            Sanitize(UserInfo_, ReturnedUser);
 | 
								SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
 | 
				
			||||||
            ReturnedUser.to_json(Me);
 | 
								Sanitize(UserInfo_, ReturnedUser);
 | 
				
			||||||
            return ReturnObject(Me);
 | 
								ReturnedUser.to_json(Me);
 | 
				
			||||||
        }
 | 
								return ReturnObject(Me);
 | 
				
			||||||
        BadRequest(RESTAPI::Errors::UnrecognizedRequest);
 | 
							}
 | 
				
			||||||
    }
 | 
							BadRequest(RESTAPI::Errors::UnrecognizedRequest);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_suboauth2_handler::DoDelete() {
 | 
						void RESTAPI_suboauth2_handler::DoDelete() {
 | 
				
			||||||
        auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
 | 
							auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
 | 
				
			||||||
        std::string SessionToken;
 | 
							std::string SessionToken;
 | 
				
			||||||
        try {
 | 
							try {
 | 
				
			||||||
            Poco::Net::OAuth20Credentials Auth(*Request);
 | 
								Poco::Net::OAuth20Credentials Auth(*Request);
 | 
				
			||||||
            if (Auth.getScheme() == "Bearer") {
 | 
								if (Auth.getScheme() == "Bearer") {
 | 
				
			||||||
                SessionToken = Auth.getBearerToken();
 | 
									SessionToken = Auth.getBearerToken();
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        } catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        if (Token.empty() || (Token != SessionToken)) {
 | 
							if (Token.empty() || (Token != SessionToken)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
								return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        AuthService()->SubLogout(Token);
 | 
							AuthService()->SubLogout(Token);
 | 
				
			||||||
        return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
 | 
							return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_suboauth2_handler::DoPost() {
 | 
						void RESTAPI_suboauth2_handler::DoPost() {
 | 
				
			||||||
        const auto & Obj = ParsedBody_;
 | 
							const auto &Obj = ParsedBody_;
 | 
				
			||||||
        auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
 | 
							auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
 | 
				
			||||||
        auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
 | 
							auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
 | 
				
			||||||
        auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
 | 
							auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
 | 
				
			||||||
        auto refreshToken = GetS("refreshToken", Obj);
 | 
							auto refreshToken = GetS("refreshToken", Obj);
 | 
				
			||||||
        auto grant_type = GetParameter("grant_type");
 | 
							auto grant_type = GetParameter("grant_type");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::toLowerInPlace(userId);
 | 
							Poco::toLowerInPlace(userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!refreshToken.empty() && grant_type == "refresh_token") {
 | 
							if (!refreshToken.empty() && grant_type == "refresh_token") {
 | 
				
			||||||
            SecurityObjects::UserInfoAndPolicy UInfo;
 | 
								SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
            if(AuthService()->RefreshSubToken(*Request, refreshToken, UInfo)) {
 | 
								if (AuthService()->RefreshSubToken(*Request, refreshToken, UInfo)) {
 | 
				
			||||||
                Poco::JSON::Object  Answer;
 | 
									Poco::JSON::Object Answer;
 | 
				
			||||||
                UInfo.webtoken.to_json(Answer);
 | 
									UInfo.webtoken.to_json(Answer);
 | 
				
			||||||
                return ReturnObject(Answer);
 | 
									return ReturnObject(Answer);
 | 
				
			||||||
            } else {
 | 
								} else {
 | 
				
			||||||
                return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
 | 
									return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
 | 
				
			||||||
            Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
 | 
								Logger_.information(
 | 
				
			||||||
            Poco::JSON::Object  Answer;
 | 
									fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->SubPasswordValidationExpression());
 | 
								Poco::JSON::Object Answer;
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy());
 | 
								Answer.set(RESTAPI::Protocol::PASSWORDPATTERN,
 | 
				
			||||||
            Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetSubPasswordPolicy());
 | 
										   AuthService()->SubPasswordValidationExpression());
 | 
				
			||||||
            return ReturnObject(Answer);
 | 
								Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy());
 | 
				
			||||||
        }
 | 
								Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetSubPasswordPolicy());
 | 
				
			||||||
 | 
								return ReturnObject(Answer);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
 | 
				
			||||||
            SecurityObjects::UserInfo UInfo1;
 | 
								SecurityObjects::UserInfo UInfo1;
 | 
				
			||||||
            auto UserExists = StorageService()->SubDB().GetUserByEmail(userId,UInfo1);
 | 
								auto UserExists = StorageService()->SubDB().GetUserByEmail(userId, UInfo1);
 | 
				
			||||||
            if(UserExists) {
 | 
								if (UserExists) {
 | 
				
			||||||
                Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId));
 | 
									Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}",
 | 
				
			||||||
                SecurityObjects::ActionLink NewLink;
 | 
																	Request->clientAddress().toString(), userId));
 | 
				
			||||||
 | 
									SecurityObjects::ActionLink NewLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
 | 
									NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
 | 
				
			||||||
                NewLink.id = MicroService::CreateUUID();
 | 
									NewLink.id = MicroServiceCreateUUID();
 | 
				
			||||||
                NewLink.userId = UInfo1.id;
 | 
									NewLink.userId = UInfo1.id;
 | 
				
			||||||
                NewLink.created = OpenWifi::Now();
 | 
									NewLink.created = OpenWifi::Now();
 | 
				
			||||||
                NewLink.expires = NewLink.created + (24*60*60);
 | 
									NewLink.expires = NewLink.created + (24 * 60 * 60);
 | 
				
			||||||
                NewLink.userAction = false;
 | 
									NewLink.userAction = false;
 | 
				
			||||||
                StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
									StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Poco::JSON::Object ReturnObj;
 | 
									Poco::JSON::Object ReturnObj;
 | 
				
			||||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
									SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
                UInfo.webtoken.userMustChangePassword = true;
 | 
									UInfo.webtoken.userMustChangePassword = true;
 | 
				
			||||||
                UInfo.webtoken.to_json(ReturnObj);
 | 
									UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
                return ReturnObject(ReturnObj);
 | 
									return ReturnObject(ReturnObj);
 | 
				
			||||||
            } else {
 | 
								} else {
 | 
				
			||||||
                Poco::JSON::Object ReturnObj;
 | 
									Poco::JSON::Object ReturnObj;
 | 
				
			||||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
									SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
                UInfo.webtoken.userMustChangePassword = true;
 | 
									UInfo.webtoken.userMustChangePassword = true;
 | 
				
			||||||
                UInfo.webtoken.to_json(ReturnObj);
 | 
									UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
                return ReturnObject(ReturnObj);
 | 
									return ReturnObject(ReturnObj);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
 | 
				
			||||||
            Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId));
 | 
								Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}",
 | 
				
			||||||
            if(Obj->has("uuid")) {
 | 
																Request->clientAddress().toString(), userId));
 | 
				
			||||||
                auto uuid = Obj->get("uuid").toString();
 | 
								if (Obj->has("uuid")) {
 | 
				
			||||||
                if(MFAServer()->ResendCode(uuid))
 | 
									auto uuid = Obj->get("uuid").toString();
 | 
				
			||||||
                    return OK();
 | 
									if (MFAServer()->ResendCode(uuid))
 | 
				
			||||||
            }
 | 
										return OK();
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
 | 
								}
 | 
				
			||||||
        }
 | 
								return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE)) {
 | 
							if (GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE)) {
 | 
				
			||||||
            Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId));
 | 
								Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}",
 | 
				
			||||||
            if(Obj->has("uuid") && Obj->has("answer")) {
 | 
																Request->clientAddress().toString(), userId));
 | 
				
			||||||
                SecurityObjects::UserInfoAndPolicy UInfo;
 | 
								if (Obj->has("uuid") && Obj->has("answer")) {
 | 
				
			||||||
                if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) {
 | 
									SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
                    Poco::JSON::Object ReturnObj;
 | 
									if (MFAServer()->CompleteMFAChallenge(Obj, UInfo)) {
 | 
				
			||||||
                    UInfo.webtoken.to_json(ReturnObj);
 | 
										Poco::JSON::Object ReturnObj;
 | 
				
			||||||
                    return ReturnObject(ReturnObj);
 | 
										UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
                }
 | 
										return ReturnObject(ReturnObj);
 | 
				
			||||||
            }
 | 
									}
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
 | 
								}
 | 
				
			||||||
        }
 | 
								return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfoAndPolicy UInfo;
 | 
							SecurityObjects::UserInfoAndPolicy UInfo;
 | 
				
			||||||
        bool Expired=false;
 | 
							bool Expired = false;
 | 
				
			||||||
        auto Code=AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired);
 | 
							auto Code = AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired);
 | 
				
			||||||
        if (Code==SUCCESS) {
 | 
							switch (Code) {
 | 
				
			||||||
            Poco::JSON::Object ReturnObj;
 | 
							case SUCCESS: {
 | 
				
			||||||
            if(AuthService()->RequiresMFA(UInfo)) {
 | 
								Poco::JSON::Object ReturnObj;
 | 
				
			||||||
                if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
 | 
								if (AuthService()->RequiresMFA(UInfo)) {
 | 
				
			||||||
                    return ReturnObject(ReturnObj);
 | 
									if (MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
 | 
				
			||||||
                }
 | 
										return ReturnObject(ReturnObj);
 | 
				
			||||||
                Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
									}
 | 
				
			||||||
            }
 | 
									Logger_.warning(
 | 
				
			||||||
            UInfo.webtoken.to_json(ReturnObj);
 | 
										"MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
				
			||||||
            return ReturnObject(ReturnObj);
 | 
								}
 | 
				
			||||||
        } else {
 | 
								UInfo.webtoken.to_json(ReturnObj);
 | 
				
			||||||
            switch(Code) {
 | 
								return ReturnObject(ReturnObj);
 | 
				
			||||||
                case INVALID_CREDENTIALS:
 | 
							}
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
							case INVALID_CREDENTIALS:
 | 
				
			||||||
                case PASSWORD_INVALID:
 | 
								return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
 | 
							case PASSWORD_INVALID:
 | 
				
			||||||
                case PASSWORD_ALREADY_USED:
 | 
								return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
 | 
							case PASSWORD_ALREADY_USED:
 | 
				
			||||||
                case USERNAME_PENDING_VERIFICATION:
 | 
								return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
 | 
							case USERNAME_PENDING_VERIFICATION:
 | 
				
			||||||
                case PASSWORD_CHANGE_REQUIRED:
 | 
								return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
 | 
							case PASSWORD_CHANGE_REQUIRED:
 | 
				
			||||||
                default:
 | 
								return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); break;
 | 
							case ACCOUNT_SUSPENDED:
 | 
				
			||||||
            }
 | 
								return UnAuthorized(RESTAPI::Errors::ACCOUNT_SUSPENDED);
 | 
				
			||||||
            return;
 | 
							default:
 | 
				
			||||||
        }
 | 
								return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
				
			||||||
    }
 | 
							}
 | 
				
			||||||
}
 | 
						}
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -3,25 +3,27 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_suboauth2_handler : public RESTAPIHandler {
 | 
						class RESTAPI_suboauth2_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
        : RESTAPIHandler(bindings, L,
 | 
													  RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                         std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
													  bool Internal)
 | 
				
			||||||
                                                  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                                  Poco::Net::HTTPRequest::HTTP_GET,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                                                  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
				
			||||||
                                                  Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
                                                  TransactionId,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                                  Internal, false, false , RateLimit{.Interval=1000,.MaxCalls=10},
 | 
												 Server, TransactionId, Internal, false, false,
 | 
				
			||||||
                                                  false) {}
 | 
												 RateLimit{.Interval = 1000, .MaxCalls = 10}, false) {}
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; };
 | 
							static auto PathName() {
 | 
				
			||||||
        void DoGet() final;
 | 
								return std::list<std::string>{"/api/v1/suboauth2/{token}", "/api/v1/suboauth2"};
 | 
				
			||||||
        void DoPost() final;
 | 
							};
 | 
				
			||||||
        void DoDelete() final;
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoPut() final {};
 | 
							void DoPost() final;
 | 
				
			||||||
    };
 | 
							void DoDelete() final;
 | 
				
			||||||
}
 | 
							void DoPut() final{};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,30 +7,30 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subpreferences::DoGet() {
 | 
						void RESTAPI_subpreferences::DoGet() {
 | 
				
			||||||
        SecurityObjects::Preferences    P;
 | 
							SecurityObjects::Preferences P;
 | 
				
			||||||
        Poco::JSON::Object  Answer;
 | 
							Poco::JSON::Object Answer;
 | 
				
			||||||
        StorageService()->SubPreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
 | 
							StorageService()->SubPreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
 | 
				
			||||||
        P.to_json(Answer);
 | 
							P.to_json(Answer);
 | 
				
			||||||
        ReturnObject(Answer);
 | 
							ReturnObject(Answer);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subpreferences::DoPut() {
 | 
						void RESTAPI_subpreferences::DoPut() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::Preferences    P;
 | 
							SecurityObjects::Preferences P;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const auto & RawObject = ParsedBody_;
 | 
							const auto &RawObject = ParsedBody_;
 | 
				
			||||||
        if(!P.from_json(RawObject)) {
 | 
							if (!P.from_json(RawObject)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
								return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        P.id = UserInfo_.userinfo.id;
 | 
							P.id = UserInfo_.userinfo.id;
 | 
				
			||||||
        P.modified = OpenWifi::Now();
 | 
							P.modified = OpenWifi::Now();
 | 
				
			||||||
        StorageService()->SubPreferencesDB().SetPreferences(P);
 | 
							StorageService()->SubPreferencesDB().SetPreferences(P);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::JSON::Object  Answer;
 | 
							Poco::JSON::Object Answer;
 | 
				
			||||||
        P.to_json(Answer);
 | 
							P.to_json(Answer);
 | 
				
			||||||
        ReturnObject(Answer);
 | 
							ReturnObject(Answer);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,24 +4,23 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_subpreferences : public RESTAPIHandler {
 | 
						class RESTAPI_subpreferences : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
        : RESTAPIHandler(bindings, L,
 | 
												   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                         std::vector<std::string>{
 | 
												   bool Internal)
 | 
				
			||||||
            Poco::Net::HTTPRequest::HTTP_GET,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
            Poco::Net::HTTPRequest::HTTP_PUT,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
            Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
				
			||||||
            Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
            TransactionId,
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
            Internal) {}
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; };
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; };
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoPut() final;
 | 
				
			||||||
        void DoPut() final;
 | 
							void DoPost() final{};
 | 
				
			||||||
        void DoPost() final {};
 | 
							void DoDelete() final{};
 | 
				
			||||||
        void DoDelete() final {};
 | 
						};
 | 
				
			||||||
    };
 | 
					} // namespace OpenWifi
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,33 +5,35 @@
 | 
				
			|||||||
#include "RESTAPI_subtotp_handler.h"
 | 
					#include "RESTAPI_subtotp_handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "TotpCache.h"
 | 
					#include "TotpCache.h"
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subtotp_handler::DoGet() {
 | 
						void RESTAPI_subtotp_handler::DoGet() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto Reset = GetBoolParameter("reset",false);
 | 
							auto Reset = GetBoolParameter("reset", false);
 | 
				
			||||||
        std::string QRCode;
 | 
							std::string QRCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(TotpCache()->StartValidation(UserInfo_.userinfo,true,QRCode,Reset)) {
 | 
							if (TotpCache()->StartValidation(UserInfo_.userinfo, true, QRCode, Reset)) {
 | 
				
			||||||
            return SendFileContent(QRCode, "image/svg+xml","qrcode.svg");
 | 
								return SendFileContent(QRCode, "image/svg+xml", "qrcode.svg");
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        return BadRequest(RESTAPI::Errors::InvalidCommand);
 | 
							return BadRequest(RESTAPI::Errors::InvalidCommand);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subtotp_handler::DoPut() {
 | 
						void RESTAPI_subtotp_handler::DoPut() {
 | 
				
			||||||
        auto Value = GetParameter("value","");
 | 
							auto Value = GetParameter("value", "");
 | 
				
			||||||
        auto nextIndex = GetParameter("index",0);
 | 
							auto nextIndex = GetParameter("index", 0);
 | 
				
			||||||
        bool moreCodes=false;
 | 
							bool moreCodes = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        RESTAPI::Errors::msg    Error;
 | 
							RESTAPI::Errors::msg Error;
 | 
				
			||||||
        if(TotpCache()->ContinueValidation(UserInfo_.userinfo,true,Value,nextIndex,moreCodes, Error )) {
 | 
							if (TotpCache()->ContinueValidation(UserInfo_.userinfo, true, Value, nextIndex, moreCodes,
 | 
				
			||||||
            Poco::JSON::Object Answer;
 | 
																Error)) {
 | 
				
			||||||
            Answer.set("nextIndex", nextIndex);
 | 
								Poco::JSON::Object Answer;
 | 
				
			||||||
            Answer.set("moreCodes", moreCodes);
 | 
								Answer.set("nextIndex", nextIndex);
 | 
				
			||||||
            return ReturnObject(Answer);
 | 
								Answer.set("moreCodes", moreCodes);
 | 
				
			||||||
        }
 | 
								return ReturnObject(Answer);
 | 
				
			||||||
        return BadRequest(Error);
 | 
							}
 | 
				
			||||||
    }
 | 
							return BadRequest(Error);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,28 +2,25 @@
 | 
				
			|||||||
// Created by stephane bourque on 2022-01-31.
 | 
					// Created by stephane bourque on 2022-01-31.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_subtotp_handler : public RESTAPIHandler {
 | 
						class RESTAPI_subtotp_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
                : RESTAPIHandler(bindings, L,
 | 
													RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                                 std::vector<std::string>
 | 
													bool Internal)
 | 
				
			||||||
                                         {
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                                                 Poco::Net::HTTPRequest::HTTP_GET,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
                                                 Poco::Net::HTTPRequest::HTTP_PUT,
 | 
																		  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
				
			||||||
                                                 Poco::Net::HTTPRequest::HTTP_OPTIONS
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                                         },
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
                                 Server,
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; };
 | 
				
			||||||
                                 TransactionId,
 | 
							void DoGet() final;
 | 
				
			||||||
                                 Internal) {}
 | 
							void DoPost() final{};
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; };
 | 
							void DoDelete() final{};
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoPut() final;
 | 
				
			||||||
        void DoPost() final {};
 | 
					 | 
				
			||||||
        void DoDelete() final {};
 | 
					 | 
				
			||||||
        void DoPut() final;
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    };
 | 
						  private:
 | 
				
			||||||
}
 | 
						};
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,314 +3,338 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTAPI_subuser_handler.h"
 | 
					#include "RESTAPI_subuser_handler.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "framework/ow_constants.h"
 | 
					 | 
				
			||||||
#include "SMSSender.h"
 | 
					 | 
				
			||||||
#include "SMTPMailerService.h"
 | 
					 | 
				
			||||||
#include "ACLProcessor.h"
 | 
					#include "ACLProcessor.h"
 | 
				
			||||||
#include "AuthService.h"
 | 
					#include "AuthService.h"
 | 
				
			||||||
#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
					 | 
				
			||||||
#include "MFAServer.h"
 | 
					#include "MFAServer.h"
 | 
				
			||||||
 | 
					#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
				
			||||||
 | 
					#include "SMSSender.h"
 | 
				
			||||||
 | 
					#include "SMTPMailerService.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
#include "TotpCache.h"
 | 
					#include "TotpCache.h"
 | 
				
			||||||
 | 
					#include "framework/ow_constants.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "framework/MicroServiceFuncs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subuser_handler::DoGet() {
 | 
						void RESTAPI_subuser_handler::DoGet() {
 | 
				
			||||||
        std::string Id = GetBinding("id", "");
 | 
							std::string Id = GetBinding("id", "");
 | 
				
			||||||
        if(Id.empty()) {
 | 
							if (Id.empty()) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
								return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::toLowerInPlace(Id);
 | 
							Poco::toLowerInPlace(Id);
 | 
				
			||||||
        std::string Arg;
 | 
							std::string Arg;
 | 
				
			||||||
        SecurityObjects::UserInfo   UInfo;
 | 
							SecurityObjects::UserInfo UInfo;
 | 
				
			||||||
        if(HasParameter("byEmail",Arg) && Arg=="true") {
 | 
							if (HasParameter("byEmail", Arg) && Arg == "true") {
 | 
				
			||||||
            if(!StorageService()->SubDB().GetUserByEmail(Id,UInfo)) {
 | 
								if (!StorageService()->SubDB().GetUserByEmail(Id, UInfo)) {
 | 
				
			||||||
                return NotFound();
 | 
									return NotFound();
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        } else if(!StorageService()->SubDB().GetUserById(Id,UInfo)) {
 | 
							} else if (!StorageService()->SubDB().GetUserById(Id, UInfo)) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::JSON::Object  UserInfoObject;
 | 
							Poco::JSON::Object UserInfoObject;
 | 
				
			||||||
        Sanitize(UserInfo_, UInfo);
 | 
							Sanitize(UserInfo_, UInfo);
 | 
				
			||||||
        UInfo.to_json(UserInfoObject);
 | 
							UInfo.to_json(UserInfoObject);
 | 
				
			||||||
        ReturnObject(UserInfoObject);
 | 
							ReturnObject(UserInfoObject);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subuser_handler::DoDelete() {
 | 
						void RESTAPI_subuser_handler::DoDelete() {
 | 
				
			||||||
        std::string Id = GetBinding("id", "");
 | 
							std::string Id = GetBinding("id", "");
 | 
				
			||||||
        if(Id.empty()) {
 | 
							if (Id.empty()) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
								return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfo TargetUser;
 | 
							SecurityObjects::UserInfo TargetUser;
 | 
				
			||||||
        if(!StorageService()->SubDB().GetUserById(Id,TargetUser)) {
 | 
							if (!StorageService()->SubDB().GetUserById(Id, TargetUser)) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(TargetUser.userRole != SecurityObjects::SUBSCRIBER) {
 | 
							if (TargetUser.userRole != SecurityObjects::SUBSCRIBER) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
								return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) {
 | 
							if (!Internal_ &&
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
								!ACLProcessor::Can(UserInfo_.userinfo, TargetUser, ACLProcessor::DELETE)) {
 | 
				
			||||||
        }
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) {
 | 
							if (!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email, Id)) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        AuthService()->DeleteSubUserFromCache(Id);
 | 
							AuthService()->DeleteSubUserFromCache(Id);
 | 
				
			||||||
        StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email);
 | 
							StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email);
 | 
				
			||||||
        StorageService()->SubPreferencesDB().DeleteRecord("id", Id);
 | 
							StorageService()->SubPreferencesDB().DeleteRecord("id", Id);
 | 
				
			||||||
        StorageService()->SubAvatarDB().DeleteRecord("id", Id);
 | 
							StorageService()->SubAvatarDB().DeleteRecord("id", Id);
 | 
				
			||||||
        Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email));
 | 
							Logger_.information(
 | 
				
			||||||
        OK();
 | 
								fmt::format("User '{}' deleted by '{}'.", Id, UserInfo_.userinfo.email));
 | 
				
			||||||
    }
 | 
							OK();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subuser_handler::DoPost() {
 | 
						void RESTAPI_subuser_handler::DoPost() {
 | 
				
			||||||
        std::string Id = GetBinding("id", "");
 | 
							std::string Id = GetBinding("id", "");
 | 
				
			||||||
        if(Id!="0") {
 | 
							if (Id != "0") {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::IdMustBe0);
 | 
								return BadRequest(RESTAPI::Errors::IdMustBe0);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfo   NewUser;
 | 
							SecurityObjects::UserInfo NewUser;
 | 
				
			||||||
        const auto & RawObject = ParsedBody_;
 | 
							const auto &RawObject = ParsedBody_;
 | 
				
			||||||
        if(!NewUser.from_json(RawObject)) {
 | 
							if (!NewUser.from_json(RawObject)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
								return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) {
 | 
							if (NewUser.userRole == SecurityObjects::UNKNOWN ||
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
								NewUser.userRole != SecurityObjects::SUBSCRIBER) {
 | 
				
			||||||
        }
 | 
								return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::toLowerInPlace(NewUser.email);
 | 
							Poco::toLowerInPlace(NewUser.email);
 | 
				
			||||||
        SecurityObjects::UserInfo   Existing;
 | 
							SecurityObjects::UserInfo Existing;
 | 
				
			||||||
        if(StorageService()->SubDB().GetUserByEmail(NewUser.email,Existing)) {
 | 
							if (StorageService()->SubDB().GetUserByEmail(NewUser.email, Existing)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::UserAlreadyExists);
 | 
								return BadRequest(RESTAPI::Errors::UserAlreadyExists);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
 | 
							if (!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, NewUser, ACLProcessor::CREATE)) {
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::toLowerInPlace(NewUser.email);
 | 
							Poco::toLowerInPlace(NewUser.email);
 | 
				
			||||||
        if(!Utils::ValidEMailAddress(NewUser.email)) {
 | 
							if (!Utils::ValidEMailAddress(NewUser.email)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
 | 
								return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!NewUser.currentPassword.empty()) {
 | 
							if (!NewUser.currentPassword.empty()) {
 | 
				
			||||||
            if(!AuthService()->ValidateSubPassword(NewUser.currentPassword)) {
 | 
								if (!AuthService()->ValidateSubPassword(NewUser.currentPassword)) {
 | 
				
			||||||
                return BadRequest(RESTAPI::Errors::InvalidPassword);
 | 
									return BadRequest(RESTAPI::Errors::InvalidPassword);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(NewUser.name.empty())
 | 
							if (NewUser.name.empty())
 | 
				
			||||||
            NewUser.name = NewUser.email;
 | 
								NewUser.name = NewUser.email;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //  You cannot enable MFA during user creation
 | 
							//  You cannot enable MFA during user creation
 | 
				
			||||||
        NewUser.userTypeProprietaryInfo.mfa.enabled = false;
 | 
							NewUser.userTypeProprietaryInfo.mfa.enabled = false;
 | 
				
			||||||
        NewUser.userTypeProprietaryInfo.mfa.method = "";
 | 
							NewUser.userTypeProprietaryInfo.mfa.method = "";
 | 
				
			||||||
        NewUser.userTypeProprietaryInfo.mobiles.clear();
 | 
							NewUser.userTypeProprietaryInfo.mobiles.clear();
 | 
				
			||||||
        NewUser.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
							NewUser.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!StorageService()->SubDB().CreateUser(UserInfo_.userinfo.email, NewUser)) {
 | 
							if (!StorageService()->SubDB().CreateUser(UserInfo_.userinfo.email, NewUser)) {
 | 
				
			||||||
            Logger_.information(fmt::format("Could not add user '{}'.",NewUser.email));
 | 
								Logger_.information(fmt::format("Could not add user '{}'.", NewUser.email));
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::RecordNotCreated);
 | 
								return BadRequest(RESTAPI::Errors::RecordNotCreated);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetParameter("email_verification","false")=="true") {
 | 
							if (GetParameter("email_verification", "false") == "true") {
 | 
				
			||||||
            if(AuthService::VerifySubEmail(NewUser))
 | 
								if (AuthService::VerifySubEmail(NewUser))
 | 
				
			||||||
                Logger_.information(fmt::format("Verification e-mail requested for {}",NewUser.email));
 | 
									Logger_.information(
 | 
				
			||||||
            StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser);
 | 
										fmt::format("Verification e-mail requested for {}", NewUser.email));
 | 
				
			||||||
        }
 | 
								StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, NewUser.id, NewUser);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!StorageService()->SubDB().GetUserByEmail(NewUser.email, NewUser)) {
 | 
							if (!StorageService()->SubDB().GetUserByEmail(NewUser.email, NewUser)) {
 | 
				
			||||||
            Logger_.information(fmt::format("User '{}' but not retrieved.",NewUser.email));
 | 
								Logger_.information(fmt::format("User '{}' but not retrieved.", NewUser.email));
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Poco::JSON::Object  UserInfoObject;
 | 
							Poco::JSON::Object UserInfoObject;
 | 
				
			||||||
        Sanitize(UserInfo_, NewUser);
 | 
							Sanitize(UserInfo_, NewUser);
 | 
				
			||||||
        NewUser.to_json(UserInfoObject);
 | 
							NewUser.to_json(UserInfoObject);
 | 
				
			||||||
        ReturnObject(UserInfoObject);
 | 
							ReturnObject(UserInfoObject);
 | 
				
			||||||
        Logger_.information(fmt::format("User '{}' has been added by '{}')",NewUser.email, UserInfo_.userinfo.email));
 | 
							Logger_.information(fmt::format("User '{}' has been added by '{}')", NewUser.email,
 | 
				
			||||||
    }
 | 
															UserInfo_.userinfo.email));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void RESTAPI_subuser_handler::DoPut() {
 | 
						void RESTAPI_subuser_handler::DoPut() {
 | 
				
			||||||
        std::string Id = GetBinding("id", "");
 | 
							std::string Id = GetBinding("id", "");
 | 
				
			||||||
        if(Id.empty()) {
 | 
							if (Id.empty()) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
								return BadRequest(RESTAPI::Errors::MissingUserID);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfo   Existing;
 | 
							SecurityObjects::UserInfo Existing;
 | 
				
			||||||
        if(!StorageService()->SubDB().GetUserById(Id,Existing)) {
 | 
							if (!StorageService()->SubDB().GetUserById(Id, Existing)) {
 | 
				
			||||||
            return NotFound();
 | 
								return NotFound();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
 | 
							if (!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, Existing, ACLProcessor::MODIFY)) {
 | 
				
			||||||
            return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
								return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter("resetMFA")) {
 | 
							if (GetBoolParameter("resetMFA")) {
 | 
				
			||||||
            if( (UserInfo_.userinfo.userRole == SecurityObjects::ROOT) ||
 | 
								if ((UserInfo_.userinfo.userRole == SecurityObjects::ROOT) ||
 | 
				
			||||||
                (UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole!=SecurityObjects::ROOT) ||
 | 
									(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN &&
 | 
				
			||||||
                (UserInfo_.userinfo.id == Id)) {
 | 
									 Existing.userRole != SecurityObjects::ROOT) ||
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mfa.enabled = false;
 | 
									(UserInfo_.userinfo.id == Id)) {
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mfa.method.clear();
 | 
									Existing.userTypeProprietaryInfo.mfa.enabled = false;
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
									Existing.userTypeProprietaryInfo.mfa.method.clear();
 | 
				
			||||||
                Existing.modified = OpenWifi::Now();
 | 
									Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
				
			||||||
                Existing.notes.push_back( SecurityObjects::NoteInfo{
 | 
									Existing.modified = OpenWifi::Now();
 | 
				
			||||||
                        .created=OpenWifi::Now(),
 | 
									Existing.notes.push_back(
 | 
				
			||||||
                        .createdBy=UserInfo_.userinfo.email,
 | 
										SecurityObjects::NoteInfo{.created = OpenWifi::Now(),
 | 
				
			||||||
                        .note="MFA Reset by " + UserInfo_.userinfo.email});
 | 
																  .createdBy = UserInfo_.userinfo.email,
 | 
				
			||||||
                StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing);
 | 
																  .note = "MFA Reset by " + UserInfo_.userinfo.email});
 | 
				
			||||||
                SecurityObjects::UserInfo   NewUserInfo;
 | 
									StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, Id, Existing);
 | 
				
			||||||
                StorageService()->SubDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
 | 
									SecurityObjects::UserInfo NewUserInfo;
 | 
				
			||||||
                Poco::JSON::Object  ModifiedObject;
 | 
									StorageService()->SubDB().GetUserByEmail(UserInfo_.userinfo.email, NewUserInfo);
 | 
				
			||||||
                Sanitize(UserInfo_, NewUserInfo);
 | 
									Poco::JSON::Object ModifiedObject;
 | 
				
			||||||
                NewUserInfo.to_json(ModifiedObject);
 | 
									Sanitize(UserInfo_, NewUserInfo);
 | 
				
			||||||
                return ReturnObject(ModifiedObject);
 | 
									NewUserInfo.to_json(ModifiedObject);
 | 
				
			||||||
            } else {
 | 
									return ReturnObject(ModifiedObject);
 | 
				
			||||||
                return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
								} else {
 | 
				
			||||||
            }
 | 
									return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
        }
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetBoolParameter("forgotPassword")) {
 | 
							if (GetBoolParameter("forgotPassword") || GetBoolParameter("resetPassword")) {
 | 
				
			||||||
            Existing.changePassword = true;
 | 
								Existing.changePassword = true;
 | 
				
			||||||
            Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), Existing.email));
 | 
								Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}",
 | 
				
			||||||
 | 
																Request->clientAddress().toString(), Existing.email));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SecurityObjects::ActionLink NewLink;
 | 
								SecurityObjects::ActionLink NewLink;
 | 
				
			||||||
            NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
 | 
								NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
 | 
				
			||||||
            NewLink.id = MicroService::CreateUUID();
 | 
								NewLink.id = MicroServiceCreateUUID();
 | 
				
			||||||
            NewLink.userId = Existing.id;
 | 
								NewLink.userId = Existing.id;
 | 
				
			||||||
            NewLink.created = OpenWifi::Now();
 | 
								NewLink.created = OpenWifi::Now();
 | 
				
			||||||
            NewLink.expires = NewLink.created + (24*60*60);
 | 
								NewLink.expires = NewLink.created + (24 * 60 * 60);
 | 
				
			||||||
            NewLink.userAction = false;
 | 
								NewLink.userAction = false;
 | 
				
			||||||
            StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
								StorageService()->ActionLinksDB().CreateAction(NewLink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return OK();
 | 
								return OK();
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SecurityObjects::UserInfo   NewUser;
 | 
							SecurityObjects::UserInfo NewUser;
 | 
				
			||||||
        const auto & RawObject = ParsedBody_;
 | 
							const auto &RawObject = ParsedBody_;
 | 
				
			||||||
        if(!NewUser.from_json(RawObject)) {
 | 
							if (!NewUser.from_json(RawObject)) {
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
								return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // some basic validations
 | 
							// some basic validations
 | 
				
			||||||
        if(RawObject->has("userRole") &&
 | 
							if (RawObject->has("userRole") &&
 | 
				
			||||||
            (SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::UNKNOWN ||
 | 
								(SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()) ==
 | 
				
			||||||
            SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::SUBSCRIBER)) {
 | 
									 SecurityObjects::UNKNOWN ||
 | 
				
			||||||
            return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
								 SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()) ==
 | 
				
			||||||
        }
 | 
									 SecurityObjects::SUBSCRIBER)) {
 | 
				
			||||||
 | 
								return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The only valid things to change are: changePassword, name,
 | 
							// The only valid things to change are: changePassword, name,
 | 
				
			||||||
        AssignIfPresent(RawObject,"name", Existing.name);
 | 
							AssignIfPresent(RawObject, "name", Existing.name);
 | 
				
			||||||
        AssignIfPresent(RawObject,"description", Existing.description);
 | 
							AssignIfPresent(RawObject, "description", Existing.description);
 | 
				
			||||||
        AssignIfPresent(RawObject,"owner", Existing.owner);
 | 
							AssignIfPresent(RawObject, "owner", Existing.owner);
 | 
				
			||||||
        AssignIfPresent(RawObject,"location", Existing.location);
 | 
							AssignIfPresent(RawObject, "location", Existing.location);
 | 
				
			||||||
        AssignIfPresent(RawObject,"locale", Existing.locale);
 | 
							AssignIfPresent(RawObject, "locale", Existing.locale);
 | 
				
			||||||
        AssignIfPresent(RawObject,"changePassword", Existing.changePassword);
 | 
							AssignIfPresent(RawObject, "changePassword", Existing.changePassword);
 | 
				
			||||||
        AssignIfPresent(RawObject,"suspended", Existing.suspended);
 | 
							AssignIfPresent(RawObject, "suspended", Existing.suspended);
 | 
				
			||||||
        AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
 | 
							AssignIfPresent(RawObject, "blackListed", Existing.blackListed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(RawObject->has("userRole")) {
 | 
							if (RawObject->has("userRole")) {
 | 
				
			||||||
            auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
 | 
								auto NewRole =
 | 
				
			||||||
            if(NewRole!=Existing.userRole) {
 | 
									SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
 | 
				
			||||||
                if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
 | 
								if (NewRole != Existing.userRole) {
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
									if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
 | 
				
			||||||
                }
 | 
										NewRole == SecurityObjects::ROOT) {
 | 
				
			||||||
                if(Id==UserInfo_.userinfo.id) {
 | 
										return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
                    return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
									}
 | 
				
			||||||
                }
 | 
									if (Id == UserInfo_.userinfo.id) {
 | 
				
			||||||
                Existing.userRole = NewRole;
 | 
										return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
				
			||||||
            }
 | 
									}
 | 
				
			||||||
        }
 | 
									Existing.userRole = NewRole;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(RawObject->has("notes")) {
 | 
							if (RawObject->has("notes")) {
 | 
				
			||||||
            SecurityObjects::NoteInfoVec NIV;
 | 
								SecurityObjects::NoteInfoVec NIV;
 | 
				
			||||||
            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
 | 
								NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(
 | 
				
			||||||
            for(auto const &i:NIV) {
 | 
									RawObject->get("notes").toString());
 | 
				
			||||||
                SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note};
 | 
								for (auto const &i : NIV) {
 | 
				
			||||||
                Existing.notes.push_back(ii);
 | 
									SecurityObjects::NoteInfo ii{.created = (uint64_t)OpenWifi::Now(),
 | 
				
			||||||
            }
 | 
																 .createdBy = UserInfo_.userinfo.email,
 | 
				
			||||||
        }
 | 
																 .note = i.note};
 | 
				
			||||||
        if(RawObject->has("currentPassword")) {
 | 
									Existing.notes.push_back(ii);
 | 
				
			||||||
            if(!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) {
 | 
								}
 | 
				
			||||||
                return BadRequest(RESTAPI::Errors::InvalidPassword);
 | 
							}
 | 
				
			||||||
            }
 | 
							if (RawObject->has("currentPassword")) {
 | 
				
			||||||
            if(!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),Existing)) {
 | 
								if (!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) {
 | 
				
			||||||
                return BadRequest(RESTAPI::Errors::PasswordRejected);
 | 
									return BadRequest(RESTAPI::Errors::InvalidPassword);
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
        }
 | 
								if (!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),
 | 
				
			||||||
 | 
																Existing)) {
 | 
				
			||||||
 | 
									return BadRequest(RESTAPI::Errors::PasswordRejected);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(GetParameter("email_verification","false")=="true") {
 | 
							if (GetParameter("email_verification", "false") == "true") {
 | 
				
			||||||
            if(AuthService::VerifySubEmail(Existing))
 | 
								if (AuthService::VerifySubEmail(Existing))
 | 
				
			||||||
                Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email));
 | 
									Logger_.information(
 | 
				
			||||||
        }
 | 
										fmt::format("Verification e-mail requested for {}", Existing.email));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(RawObject->has("userTypeProprietaryInfo")) {
 | 
							if (RawObject->has("userTypeProprietaryInfo")) {
 | 
				
			||||||
            if(NewUser.userTypeProprietaryInfo.mfa.enabled) {
 | 
								if (NewUser.userTypeProprietaryInfo.mfa.enabled) {
 | 
				
			||||||
                if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) {
 | 
									if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) {
 | 
				
			||||||
                    return BadRequest(RESTAPI::Errors::BadMFAMethod);
 | 
										return BadRequest(RESTAPI::Errors::BadMFAMethod);
 | 
				
			||||||
                }
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if( NewUser.userTypeProprietaryInfo.mfa.enabled &&
 | 
									if (NewUser.userTypeProprietaryInfo.mfa.enabled &&
 | 
				
			||||||
                    NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS &&
 | 
										NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS &&
 | 
				
			||||||
                    !SMSSender()->Enabled()) {
 | 
										!SMSSender()->Enabled()) {
 | 
				
			||||||
                    return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
 | 
										return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
 | 
				
			||||||
                }
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if( NewUser.userTypeProprietaryInfo.mfa.enabled &&
 | 
									if (NewUser.userTypeProprietaryInfo.mfa.enabled &&
 | 
				
			||||||
                    NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL &&
 | 
										NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL &&
 | 
				
			||||||
                    !SMTPMailerService()->Enabled()) {
 | 
										!SMTPMailerService()->Enabled()) {
 | 
				
			||||||
                    return BadRequest(RESTAPI::Errors::EMailMFANotEnabled);
 | 
										return BadRequest(RESTAPI::Errors::EMailMFANotEnabled);
 | 
				
			||||||
                }
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method;
 | 
									Existing.userTypeProprietaryInfo.mfa.method =
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mfa.enabled = true;
 | 
										NewUser.userTypeProprietaryInfo.mfa.method;
 | 
				
			||||||
 | 
									Existing.userTypeProprietaryInfo.mfa.enabled = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
 | 
									if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
 | 
				
			||||||
                    if(NewUser.userTypeProprietaryInfo.mobiles.empty()) {
 | 
										if (NewUser.userTypeProprietaryInfo.mobiles.empty()) {
 | 
				
			||||||
                        return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
											return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
				
			||||||
                    }
 | 
										}
 | 
				
			||||||
                    if (!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)) {
 | 
										if (!SMSSender()->IsNumberValid(
 | 
				
			||||||
                        return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
												NewUser.userTypeProprietaryInfo.mobiles[0].number,
 | 
				
			||||||
                    }
 | 
												UserInfo_.userinfo.email)) {
 | 
				
			||||||
                    Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
 | 
											return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
				
			||||||
                    Existing.userTypeProprietaryInfo.mobiles[0].verified = true;
 | 
										}
 | 
				
			||||||
                    Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
										Existing.userTypeProprietaryInfo.mobiles =
 | 
				
			||||||
                } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) {
 | 
											NewUser.userTypeProprietaryInfo.mobiles;
 | 
				
			||||||
                    std::string Secret;
 | 
										Existing.userTypeProprietaryInfo.mobiles[0].verified = true;
 | 
				
			||||||
                    Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
										Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
				
			||||||
                    if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) {
 | 
									} else if (NewUser.userTypeProprietaryInfo.mfa.method ==
 | 
				
			||||||
                        Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
 | 
											   MFAMETHODS::AUTHENTICATOR) {
 | 
				
			||||||
                    } else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
 | 
										std::string Secret;
 | 
				
			||||||
                        // we allow someone to use their old secret
 | 
										Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
				
			||||||
                    } else {
 | 
										if (Existing.userTypeProprietaryInfo.authenticatorSecret.empty() &&
 | 
				
			||||||
                        return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete);
 | 
											TotpCache()->CompleteValidation(UserInfo_.userinfo, false, Secret)) {
 | 
				
			||||||
                    }
 | 
											Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
 | 
				
			||||||
                } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) {
 | 
										} else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
 | 
				
			||||||
                    Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
											// we allow someone to use their old secret
 | 
				
			||||||
                    Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
										} else {
 | 
				
			||||||
                }
 | 
											return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete);
 | 
				
			||||||
            } else {
 | 
										}
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
									} else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) {
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
										Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
				
			||||||
                Existing.userTypeProprietaryInfo.mfa.enabled = false;
 | 
										Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
				
			||||||
            }
 | 
									}
 | 
				
			||||||
        }
 | 
								} else {
 | 
				
			||||||
 | 
									Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
				
			||||||
 | 
									Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
				
			||||||
 | 
									Existing.userTypeProprietaryInfo.mfa.enabled = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
 | 
							if (StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, Id, Existing)) {
 | 
				
			||||||
            SecurityObjects::UserInfo   NewUserInfo;
 | 
								SecurityObjects::UserInfo NewUserInfo;
 | 
				
			||||||
            StorageService()->SubDB().GetUserById(Id,NewUserInfo);
 | 
								StorageService()->SubDB().GetUserById(Id, NewUserInfo);
 | 
				
			||||||
            Poco::JSON::Object  ModifiedObject;
 | 
								Poco::JSON::Object ModifiedObject;
 | 
				
			||||||
            Sanitize(UserInfo_, NewUserInfo);
 | 
								Sanitize(UserInfo_, NewUserInfo);
 | 
				
			||||||
            NewUserInfo.to_json(ModifiedObject);
 | 
								NewUserInfo.to_json(ModifiedObject);
 | 
				
			||||||
            return ReturnObject(ModifiedObject);
 | 
								return ReturnObject(ModifiedObject);
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        BadRequest(RESTAPI::Errors::RecordNotUpdated);
 | 
							BadRequest(RESTAPI::Errors::RecordNotUpdated);
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
}
 | 
					} // namespace OpenWifi
 | 
				
			||||||
@@ -4,28 +4,27 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/MicroService.h"
 | 
					#include "framework/RESTAPI_Handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
    class RESTAPI_subuser_handler : public RESTAPIHandler {
 | 
						class RESTAPI_subuser_handler : public RESTAPIHandler {
 | 
				
			||||||
    public:
 | 
						  public:
 | 
				
			||||||
        RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
							RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
				
			||||||
        : RESTAPIHandler(bindings, L,
 | 
													RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
				
			||||||
                         std::vector<std::string>
 | 
													bool Internal)
 | 
				
			||||||
                         {Poco::Net::HTTPRequest::HTTP_POST,
 | 
								: RESTAPIHandler(bindings, L,
 | 
				
			||||||
                          Poco::Net::HTTPRequest::HTTP_GET,
 | 
												 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
				
			||||||
                          Poco::Net::HTTPRequest::HTTP_PUT,
 | 
																		  Poco::Net::HTTPRequest::HTTP_GET,
 | 
				
			||||||
                          Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
																		  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
				
			||||||
                          Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
																		  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
				
			||||||
                          Server,
 | 
																		  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
				
			||||||
                          TransactionId,
 | 
												 Server, TransactionId, Internal) {}
 | 
				
			||||||
                          Internal) {}
 | 
							static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; };
 | 
				
			||||||
        static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; };
 | 
							void DoGet() final;
 | 
				
			||||||
        void DoGet() final;
 | 
							void DoPost() final;
 | 
				
			||||||
        void DoPost() final;
 | 
							void DoDelete() final;
 | 
				
			||||||
        void DoDelete() final;
 | 
							void DoPut() final;
 | 
				
			||||||
        void DoPut() final;
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    };
 | 
						  private:
 | 
				
			||||||
}
 | 
						};
 | 
				
			||||||
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||