daily commit
This commit is contained in:
4
.env
Normal file
4
.env
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
POSTGRES_USER="admin"
|
||||||
|
POSTGRES_PASSWORD="admin"
|
||||||
|
KEYCLOAK_ADMIN_PASSWORD="admin"
|
||||||
|
KC_HOSTNAME="localhost"
|
||||||
10
.idea/.gitignore
generated
vendored
Normal file
10
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Ignored default folder with query files
|
||||||
|
/queries/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
345
.idea/editor.xml
generated
Normal file
345
.idea/editor.xml
generated
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="BackendCodeEditorSettings">
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefinitionsOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedOverridenMethod/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppModulePartitionWithSeveralPartitionUnits/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantFwdClassOrEnumSpecifier/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifierADL/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
11
.idea/gas-delivery-backend.iml
generated
Normal file
11
.idea/gas-delivery-backend.iml
generated
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="CPP_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
46
.idea/misc.xml
generated
Normal file
46
.idea/misc.xml
generated
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||||
|
<entry key="Project Default">
|
||||||
|
<profile-state>
|
||||||
|
<expanded-state>
|
||||||
|
<State>
|
||||||
|
<id>Async code and promisesJavaScript and TypeScript</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>C/C++</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>JavaScript and TypeScript</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>Pandas</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>Potential Code Quality IssuesC/C++</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>Python</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>ReactJavaScript and TypeScript</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>RegExp</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>TypeScriptJavaScript and TypeScript</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>XPath</id>
|
||||||
|
</State>
|
||||||
|
</expanded-state>
|
||||||
|
<selected-state>
|
||||||
|
<State>
|
||||||
|
<id>User defined</id>
|
||||||
|
</State>
|
||||||
|
</selected-state>
|
||||||
|
</profile-state>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/gas-delivery-backend.iml" filepath="$PROJECT_DIR$/.idea/gas-delivery-backend.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
2954
Cargo.lock
generated
Normal file
2954
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "delivery-backend"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
axum = "0.8.6"
|
||||||
|
axum-keycloak-auth = "0.8.3"
|
||||||
|
chrono = "0.4.42"
|
||||||
|
log = "0.4.28"
|
||||||
|
redis = { version = "0.32.6", features = ["connection-manager", "tokio-comp"] }
|
||||||
|
reqwest = { version = "0.12.23", features = ["json"] }
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
serde_json = "1.0.145"
|
||||||
|
simplelog = "0.12.2"
|
||||||
|
tokio = { version = "1.47.1", features = ["full"] }
|
||||||
|
toml = "0.9.7"
|
||||||
|
oauth2 = "5.0.0"
|
||||||
|
uuid = "1.18.1"
|
||||||
|
axum-extra = { version = "0.10.3", features = ["cookie", "typed-header", "json-deserializer"] }
|
||||||
|
base64 = "0.22.1"
|
||||||
48
Dockerfile
Normal file
48
Dockerfile
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM rust:1.90.0-slim-trixie as builder
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy manifests
|
||||||
|
COPY Cargo.toml Cargo.lock ./
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
# Install runtime dependencies (if needed, e.g., for SSL)
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends ca-certificates libssl-dev pkg-config && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Build for release
|
||||||
|
RUN cargo build --release
|
||||||
|
|
||||||
|
# Runtime stage
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
# Install runtime dependencies (if needed, e.g., for SSL)
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends ca-certificates libssl-dev && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
RUN useradd -m -u 1000 appuser
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy only the binary from builder
|
||||||
|
COPY --from=builder /app/target/release/delivery-backend /app/service
|
||||||
|
|
||||||
|
# Change ownership to non-root user
|
||||||
|
RUN chown -R appuser:appuser /app
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Expose port (adjust as needed)
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Run the binary
|
||||||
|
CMD ["/app/service"]
|
||||||
@ -1,3 +1 @@
|
|||||||
# gas-delivery-backend
|
# Lieferservice Rust Backend
|
||||||
|
|
||||||
Das Projekt dient als Testumgebung, ohne auf GSD-Software angewiesen zu sein.
|
|
||||||
20
config.toml
Normal file
20
config.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
log_file_prefix = "delivery_backend"
|
||||||
|
host_ip = "127.0.0.1"
|
||||||
|
host_port = 3000
|
||||||
|
redis_url = "redis://127.0.0.1:6379"
|
||||||
|
frontend_url = "myapp://callback"
|
||||||
|
gsd_app_key = "GSD-RestApi"
|
||||||
|
gsd_rest_url = "http://127.0.0.1:8334"
|
||||||
|
gsd_user = "<GSD-USER>"
|
||||||
|
gsd_password = "<GSD-Password>"
|
||||||
|
gsd_app_names = ["GSD-RestApi"]
|
||||||
|
|
||||||
|
[keycloak]
|
||||||
|
realm_url = "http://127.0.0.1:8080/realms/master"
|
||||||
|
client_id = "delivery-app"
|
||||||
|
client_secret = "Re9pifaHT78PY5CjE3UaCiAxyq5oawTU"
|
||||||
|
auth_url = "http://127.0.0.1:8080/realms/master/protocol/openid-connect/auth"
|
||||||
|
token_url = "http://127.0.0.1:8080/realms/master/protocol/openid-connect/token"
|
||||||
|
redirect_url = "http://127.0.0.1:3000/callback"
|
||||||
|
realm = "master"
|
||||||
|
base_url = "http://127.0.0.1:8080"
|
||||||
20
config.toml.example
Normal file
20
config.toml.example
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
log_file_prefix = "delivery_backend"
|
||||||
|
host_ip = "127.0.0.1"
|
||||||
|
host_port = 3000
|
||||||
|
redis_url = "redis://127.0.0.1:6379"
|
||||||
|
gsd_app_key = "GSD-RestApi"
|
||||||
|
frontend_url = "http://127.0.0.1:3000"
|
||||||
|
gsd_rest_url = "http://127.0.0.1:8334"
|
||||||
|
gsd_user = "GSDWebServiceTmp"
|
||||||
|
gsd_password = "admin"
|
||||||
|
gsd_app_names = ["GSD-RestApi"]
|
||||||
|
|
||||||
|
[keycloak]
|
||||||
|
realm_url = "http://localhost:8080/realms/master"
|
||||||
|
client_id = "delivery-app"
|
||||||
|
client_secret = "<SECRET>"
|
||||||
|
realm = "<REALM>>"
|
||||||
|
base_url = "<BASE_URL>"
|
||||||
|
auth_url = "http://localhost:8080/realms/master/protocol/openid-connect/auth"
|
||||||
|
token_url = "http://localhost:8080/realms/master/protocol/openid-connect/token"
|
||||||
|
redirect_url = "http://127.0.0.1:3000/callback"
|
||||||
17
delivery_backend_2026-02-03T12-43-33.919547+0100.log
Normal file
17
delivery_backend_2026-02-03T12-43-33.919547+0100.log
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
11:43:33 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
11:43:33 [INFO] Logging initialized
|
||||||
|
11:43:33 [INFO] Starting Gas Delivery Backend
|
||||||
|
11:43:33 [INFO] Initializing redis server
|
||||||
|
11:43:33 [INFO] Starting axum server
|
||||||
|
11:43:33 [INFO] perform_oidc_discovery; kc_instance_id=019c2350-a621-7891-b1e7-8cd16bb3ea5d kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
11:43:33 [INFO] layer; id=019c2350-a621-7891-b1e7-8cefbc7c05e3
|
||||||
|
11:43:33 [INFO] Starting OIDC discovery.
|
||||||
|
11:43:33 [INFO] layer; id=019c2350-a621-7891-b1e7-8cefbc7c05e3
|
||||||
|
11:43:33 [INFO] layer; id=019c2350-a621-7891-b1e7-8cefbc7c05e3
|
||||||
|
11:43:33 [INFO] layer; id=019c2350-a621-7891-b1e7-8cefbc7c05e3
|
||||||
|
11:43:33 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
11:43:33 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
11:43:36 [INFO] Access token expired for session 019c233e-192e-7e01-9f6f-2420edb77530, attempting refresh
|
||||||
|
11:43:36 [INFO] Successfully refreshed access token for session 019c233e-192e-7e01-9f6f-2420edb77530
|
||||||
|
11:45:48 [INFO] Access token expired for session 019c233e-192e-7e01-9f6f-2420edb77530, attempting refresh
|
||||||
|
11:45:48 [INFO] Successfully refreshed access token for session 019c233e-192e-7e01-9f6f-2420edb77530
|
||||||
14
delivery_backend_2026-02-03T12-45-54.710930+0100.log
Normal file
14
delivery_backend_2026-02-03T12-45-54.710930+0100.log
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
11:45:54 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
11:45:54 [INFO] Logging initialized
|
||||||
|
11:45:54 [INFO] Starting Gas Delivery Backend
|
||||||
|
11:45:54 [INFO] Initializing redis server
|
||||||
|
11:45:54 [INFO] Starting axum server
|
||||||
|
11:45:54 [INFO] perform_oidc_discovery; kc_instance_id=019c2352-cc18-7591-9646-c102294a1e16 kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
11:45:54 [INFO] layer; id=019c2352-cc19-7c60-9105-7ff0e0c191d3
|
||||||
|
11:45:54 [INFO] Starting OIDC discovery.
|
||||||
|
11:45:54 [INFO] layer; id=019c2352-cc19-7c60-9105-7ff0e0c191d3
|
||||||
|
11:45:54 [INFO] layer; id=019c2352-cc19-7c60-9105-7ff0e0c191d3
|
||||||
|
11:45:54 [INFO] layer; id=019c2352-cc19-7c60-9105-7ff0e0c191d3
|
||||||
|
11:45:54 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
11:45:54 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
11:46:02 [INFO] Access token still valid for session 019c233e-192e-7e01-9f6f-2420edb77530 (expires in 46 seconds)
|
||||||
15
delivery_backend_2026-02-03T12-46-53.579098+0100.log
Normal file
15
delivery_backend_2026-02-03T12-46-53.579098+0100.log
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
11:46:53 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
11:46:53 [INFO] Logging initialized
|
||||||
|
11:46:53 [INFO] Starting Gas Delivery Backend
|
||||||
|
11:46:53 [INFO] Initializing redis server
|
||||||
|
11:46:53 [INFO] Starting axum server
|
||||||
|
11:46:53 [INFO] perform_oidc_discovery; kc_instance_id=019c2353-b20d-7311-ac2a-05e277a1e841 kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
11:46:53 [INFO] layer; id=019c2353-b20e-73b2-92d0-194d33673bd9
|
||||||
|
11:46:53 [INFO] Starting OIDC discovery.
|
||||||
|
11:46:53 [INFO] layer; id=019c2353-b20e-73b2-92d0-194d33673bd9
|
||||||
|
11:46:53 [INFO] layer; id=019c2353-b20e-73b2-92d0-194d33673bd9
|
||||||
|
11:46:53 [INFO] layer; id=019c2353-b20e-73b2-92d0-194d33673bd9
|
||||||
|
11:46:53 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
11:46:53 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
11:46:59 [INFO] Access token expired for session 019c233e-192e-7e01-9f6f-2420edb77530, attempting refresh
|
||||||
|
11:46:59 [INFO] Successfully refreshed access token for session 019c233e-192e-7e01-9f6f-2420edb77530
|
||||||
14
delivery_backend_2026-02-03T12-47-20.226433+0100.log
Normal file
14
delivery_backend_2026-02-03T12-47-20.226433+0100.log
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
11:47:20 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
11:47:20 [INFO] Logging initialized
|
||||||
|
11:47:20 [INFO] Starting Gas Delivery Backend
|
||||||
|
11:47:20 [INFO] Initializing redis server
|
||||||
|
11:47:20 [INFO] Starting axum server
|
||||||
|
11:47:20 [INFO] perform_oidc_discovery; kc_instance_id=019c2354-1a24-77f1-9e59-1653ab679598 kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
11:47:20 [INFO] layer; id=019c2354-1a24-77f1-9e59-166e393ee02f
|
||||||
|
11:47:20 [INFO] Starting OIDC discovery.
|
||||||
|
11:47:20 [INFO] layer; id=019c2354-1a24-77f1-9e59-166e393ee02f
|
||||||
|
11:47:20 [INFO] layer; id=019c2354-1a24-77f1-9e59-166e393ee02f
|
||||||
|
11:47:20 [INFO] layer; id=019c2354-1a24-77f1-9e59-166e393ee02f
|
||||||
|
11:47:20 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
11:47:20 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
11:47:29 [INFO] Access token still valid for session 019c233e-192e-7e01-9f6f-2420edb77530 (expires in 30 seconds)
|
||||||
23
delivery_backend_2026-02-03T12-47-53.258106+0100.log
Normal file
23
delivery_backend_2026-02-03T12-47-53.258106+0100.log
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
11:47:53 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
11:47:53 [INFO] Logging initialized
|
||||||
|
11:47:53 [INFO] Starting Gas Delivery Backend
|
||||||
|
11:47:53 [INFO] Initializing redis server
|
||||||
|
11:47:53 [INFO] Starting axum server
|
||||||
|
11:47:53 [INFO] perform_oidc_discovery; kc_instance_id=019c2354-9b2b-77f0-958c-55e31e57410c kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
11:47:53 [INFO] layer; id=019c2354-9b2b-77f0-958c-55f0558b380d
|
||||||
|
11:47:53 [INFO] Starting OIDC discovery.
|
||||||
|
11:47:53 [INFO] layer; id=019c2354-9b2b-77f0-958c-55f0558b380d
|
||||||
|
11:47:53 [INFO] layer; id=019c2354-9b2b-77f0-958c-55f0558b380d
|
||||||
|
11:47:53 [INFO] layer; id=019c2354-9b2b-77f0-958c-55f0558b380d
|
||||||
|
11:47:53 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
11:47:53 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
12:03:31 [INFO] Callback called
|
||||||
|
12:03:31 [INFO] Successfully created session 019c2362-edbd-77b1-a0bd-8c29f4bdf257 for user
|
||||||
|
12:03:31 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
12:03:32 [INFO] Access token still valid for session 019c2362-edbd-77b1-a0bd-8c29f4bdf257 (expires in 59 seconds)
|
||||||
|
12:03:56 [INFO] Callback called
|
||||||
|
12:03:56 [INFO] Successfully created session 019c2363-4d78-74c2-96db-9e1faced3c74 for user
|
||||||
|
12:03:56 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
12:03:56 [INFO] Access token still valid for session 019c2363-4d78-74c2-96db-9e1faced3c74 (expires in 60 seconds)
|
||||||
|
12:05:45 [INFO] Access token expired for session 019c233e-192e-7e01-9f6f-2420edb77530, attempting refresh
|
||||||
|
12:05:45 [INFO] Successfully refreshed access token for session 019c233e-192e-7e01-9f6f-2420edb77530
|
||||||
13
delivery_backend_2026-02-03T13-08-35.401063+0100.log
Normal file
13
delivery_backend_2026-02-03T13-08-35.401063+0100.log
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
12:08:35 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
12:08:35 [INFO] Logging initialized
|
||||||
|
12:08:35 [INFO] Starting Gas Delivery Backend
|
||||||
|
12:08:35 [INFO] Initializing redis server
|
||||||
|
12:08:35 [INFO] Starting axum server
|
||||||
|
12:08:35 [INFO] perform_oidc_discovery; kc_instance_id=019c2367-8f4e-7ec1-809b-abded76bf656 kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
12:08:35 [INFO] layer; id=019c2367-8f4e-7ec1-809b-abeed90ad1b9
|
||||||
|
12:08:35 [INFO] Starting OIDC discovery.
|
||||||
|
12:08:35 [INFO] layer; id=019c2367-8f4e-7ec1-809b-abeed90ad1b9
|
||||||
|
12:08:35 [INFO] layer; id=019c2367-8f4e-7ec1-809b-abeed90ad1b9
|
||||||
|
12:08:35 [INFO] layer; id=019c2367-8f4e-7ec1-809b-abeed90ad1b9
|
||||||
|
12:08:35 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
12:08:35 [INFO] Received new jwk_set containing 2 keys.
|
||||||
25
delivery_backend_2026-02-03T13-10-33.652283+0100.log
Normal file
25
delivery_backend_2026-02-03T13-10-33.652283+0100.log
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
12:10:33 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
12:10:33 [INFO] Logging initialized
|
||||||
|
12:10:33 [INFO] Starting Gas Delivery Backend
|
||||||
|
12:10:33 [INFO] Initializing redis server
|
||||||
|
12:10:33 [INFO] Starting axum server
|
||||||
|
12:10:33 [INFO] perform_oidc_discovery; kc_instance_id=019c2369-5d36-74f2-a278-d98f6f997d4c kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
12:10:33 [INFO] Starting OIDC discovery.
|
||||||
|
12:10:33 [INFO] layer; id=019c2369-5d36-74f2-a278-d993e2a77fb3
|
||||||
|
12:10:33 [INFO] layer; id=019c2369-5d36-74f2-a278-d993e2a77fb3
|
||||||
|
12:10:33 [INFO] layer; id=019c2369-5d36-74f2-a278-d993e2a77fb3
|
||||||
|
12:10:33 [INFO] layer; id=019c2369-5d36-74f2-a278-d993e2a77fb3
|
||||||
|
12:10:33 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
12:10:33 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
12:10:52 [INFO] Callback called
|
||||||
|
12:10:52 [INFO] Successfully created session 019c2369-a8af-74c3-b516-6ab502c10865 for user
|
||||||
|
12:10:52 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
12:10:53 [INFO] Access token still valid for session 019c2369-a8af-74c3-b516-6ab502c10865 (expires in 59 seconds)
|
||||||
|
13:57:06 [INFO] Callback called
|
||||||
|
13:57:06 [INFO] Successfully created session 019c23ca-e7f5-7702-87b3-d30e6b39caea for user
|
||||||
|
13:57:06 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:57:06 [INFO] Access token still valid for session 019c23ca-e7f5-7702-87b3-d30e6b39caea (expires in 60 seconds)
|
||||||
|
14:47:54 [INFO] Callback called
|
||||||
|
14:47:54 [INFO] Successfully created session 019c23f9-6cdd-7bc1-9221-6fd100ba718b for user
|
||||||
|
14:47:54 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
14:47:55 [INFO] Access token still valid for session 019c23f9-6cdd-7bc1-9221-6fd100ba718b (expires in 59 seconds)
|
||||||
17
delivery_backend_2026-02-04T13-17-23.075534+0100.log
Normal file
17
delivery_backend_2026-02-04T13-17-23.075534+0100.log
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
12:17:23 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
12:17:23 [INFO] Logging initialized
|
||||||
|
12:17:23 [INFO] Starting Gas Delivery Backend
|
||||||
|
12:17:23 [INFO] Initializing redis server
|
||||||
|
12:17:23 [INFO] Starting axum server
|
||||||
|
12:17:23 [INFO] perform_oidc_discovery; kc_instance_id=019c2895-f887-7350-b9f6-6c8f37d12eb6 kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
12:17:23 [INFO] layer; id=019c2895-f888-7bc3-a601-00e1535f7d9d
|
||||||
|
12:17:23 [INFO] Starting OIDC discovery.
|
||||||
|
12:17:23 [INFO] layer; id=019c2895-f888-7bc3-a601-00e1535f7d9d
|
||||||
|
12:17:23 [INFO] layer; id=019c2895-f888-7bc3-a601-00e1535f7d9d
|
||||||
|
12:17:23 [INFO] layer; id=019c2895-f888-7bc3-a601-00e1535f7d9d
|
||||||
|
12:17:23 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
12:17:23 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
12:17:38 [INFO] Callback called
|
||||||
|
12:17:38 [INFO] Successfully created session 019c2896-34eb-7ed0-9b1a-59f54c9a44c9 for user
|
||||||
|
12:17:38 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
12:17:38 [INFO] Access token still valid for session 019c2896-34eb-7ed0-9b1a-59f54c9a44c9 (expires in 60 seconds)
|
||||||
20
delivery_backend_2026-02-04T13-40-32.031715+0100.log
Normal file
20
delivery_backend_2026-02-04T13-40-32.031715+0100.log
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
12:40:32 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
12:40:32 [INFO] Logging initialized
|
||||||
|
12:40:32 [INFO] Starting Gas Delivery Backend
|
||||||
|
12:40:32 [INFO] Initializing redis server
|
||||||
|
12:40:32 [INFO] Starting axum server
|
||||||
|
12:40:32 [INFO] perform_oidc_discovery; kc_instance_id=019c28ab-2a25-7051-b0b2-83f13f1f783f kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
12:40:32 [INFO] Starting OIDC discovery.
|
||||||
|
12:40:32 [INFO] layer; id=019c28ab-2a25-7051-b0b2-84014d120574
|
||||||
|
12:40:32 [INFO] layer; id=019c28ab-2a25-7051-b0b2-84014d120574
|
||||||
|
12:40:32 [INFO] layer; id=019c28ab-2a25-7051-b0b2-84014d120574
|
||||||
|
12:40:32 [INFO] layer; id=019c28ab-2a25-7051-b0b2-84014d120574
|
||||||
|
12:40:32 [INFO] layer; id=019c28ab-2a25-7051-b0b2-84014d120574
|
||||||
|
12:40:32 [INFO] layer; id=019c28ab-2a25-7051-b0b2-84014d120574
|
||||||
|
12:40:32 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
12:40:32 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
12:41:38 [INFO] Callback called
|
||||||
|
12:41:38 [INFO] Successfully created session 019c28ac-2f5a-75e1-b909-f862e773a5c6 for user
|
||||||
|
12:41:38 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
12:41:39 [INFO] Access token still valid for session 019c28ac-2f5a-75e1-b909-f862e773a5c6 (expires in 59 seconds)
|
||||||
|
12:42:33 [INFO] Access token still valid for session 019c28ac-2f5a-75e1-b909-f862e773a5c6 (expires in 5 seconds)
|
||||||
42
delivery_backend_2026-02-04T13-44-41.844934+0100.log
Normal file
42
delivery_backend_2026-02-04T13-44-41.844934+0100.log
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
12:44:41 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
12:44:41 [INFO] Logging initialized
|
||||||
|
12:44:41 [INFO] Starting Gas Delivery Backend
|
||||||
|
12:44:41 [INFO] Initializing redis server
|
||||||
|
12:44:41 [INFO] Starting axum server
|
||||||
|
12:44:41 [INFO] perform_oidc_discovery; kc_instance_id=019c28ae-f9fa-7ad0-b4b8-4c583e97ed32 kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
12:44:41 [INFO] Starting OIDC discovery.
|
||||||
|
12:44:41 [INFO] layer; id=019c28ae-f9fa-7ad0-b4b8-4c60b26bdea9
|
||||||
|
12:44:41 [INFO] layer; id=019c28ae-f9fa-7ad0-b4b8-4c60b26bdea9
|
||||||
|
12:44:41 [INFO] layer; id=019c28ae-f9fa-7ad0-b4b8-4c60b26bdea9
|
||||||
|
12:44:41 [INFO] layer; id=019c28ae-f9fa-7ad0-b4b8-4c60b26bdea9
|
||||||
|
12:44:41 [INFO] layer; id=019c28ae-f9fa-7ad0-b4b8-4c60b26bdea9
|
||||||
|
12:44:41 [INFO] layer; id=019c28ae-f9fa-7ad0-b4b8-4c60b26bdea9
|
||||||
|
12:44:41 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
12:44:41 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
12:44:47 [INFO] Access token expired for session 019c28ac-2f5a-75e1-b909-f862e773a5c6, attempting refresh
|
||||||
|
12:44:47 [INFO] Successfully refreshed access token for session 019c28ac-2f5a-75e1-b909-f862e773a5c6
|
||||||
|
13:05:19 [INFO] Callback called
|
||||||
|
13:05:19 [INFO] Successfully created session 019c28c1-db02-7261-aa2e-a2f0f7485080 for user
|
||||||
|
13:05:19 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:05:19 [INFO] Access token still valid for session 019c28c1-db02-7261-aa2e-a2f0f7485080 (expires in 60 seconds)
|
||||||
|
13:06:09 [INFO] Callback called
|
||||||
|
13:06:09 [INFO] Successfully created session 019c28c2-a14b-7e13-8593-7181dc374eca for user
|
||||||
|
13:06:09 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:06:11 [INFO] Callback called
|
||||||
|
13:06:11 [INFO] Successfully created session 019c28c2-a76f-7562-a2b5-197e2d42dbce for user
|
||||||
|
13:06:11 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:06:13 [INFO] Callback called
|
||||||
|
13:06:13 [INFO] Successfully created session 019c28c2-aed9-7932-b206-a19549ec754d for user
|
||||||
|
13:06:13 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:06:23 [INFO] Callback called
|
||||||
|
13:06:23 [INFO] Successfully created session 019c28c2-d540-7271-b0aa-dc302a522d1b for user
|
||||||
|
13:06:23 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:06:23 [INFO] Access token still valid for session 019c28c2-d540-7271-b0aa-dc302a522d1b (expires in 60 seconds)
|
||||||
|
13:07:25 [INFO] Callback called
|
||||||
|
13:07:25 [INFO] Successfully created session 019c28c3-ca65-7020-afe3-3adbaf4d57f9 for user
|
||||||
|
13:07:25 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:07:26 [INFO] Access token still valid for session 019c28c3-ca65-7020-afe3-3adbaf4d57f9 (expires in 59 seconds)
|
||||||
|
13:08:11 [INFO] Callback called
|
||||||
|
13:08:11 [INFO] Successfully created session 019c28c4-7db5-7ea3-be74-f77bf07e7f09 for user
|
||||||
|
13:08:11 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:08:12 [INFO] Access token still valid for session 019c28c4-7db5-7ea3-be74-f77bf07e7f09 (expires in 59 seconds)
|
||||||
102
delivery_backend_2026-02-04T14-08-37.947867+0100.log
Normal file
102
delivery_backend_2026-02-04T14-08-37.947867+0100.log
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
13:08:37 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
13:08:37 [INFO] Logging initialized
|
||||||
|
13:08:37 [INFO] Starting Gas Delivery Backend
|
||||||
|
13:08:37 [INFO] Initializing redis server
|
||||||
|
13:08:37 [INFO] Starting axum server
|
||||||
|
13:08:37 [INFO] perform_oidc_discovery; kc_instance_id=019c28c4-e3be-7b41-8e29-eeee14d213d3 kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
13:08:37 [INFO] Starting OIDC discovery.
|
||||||
|
13:08:37 [INFO] layer; id=019c28c4-e3be-7b41-8e29-eef7556770a3
|
||||||
|
13:08:37 [INFO] layer; id=019c28c4-e3be-7b41-8e29-eef7556770a3
|
||||||
|
13:08:37 [INFO] layer; id=019c28c4-e3be-7b41-8e29-eef7556770a3
|
||||||
|
13:08:37 [INFO] layer; id=019c28c4-e3be-7b41-8e29-eef7556770a3
|
||||||
|
13:08:37 [INFO] layer; id=019c28c4-e3be-7b41-8e29-eef7556770a3
|
||||||
|
13:08:37 [INFO] layer; id=019c28c4-e3be-7b41-8e29-eef7556770a3
|
||||||
|
13:08:37 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
13:08:38 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
13:09:19 [INFO] Callback called
|
||||||
|
13:09:19 [INFO] Successfully created session 019c28c5-8655-74d1-9e57-2a132b1213cb for user
|
||||||
|
13:09:19 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:09:19 [INFO] Access token still valid for session 019c28c5-8655-74d1-9e57-2a132b1213cb (expires in 60 seconds)
|
||||||
|
13:09:22 [INFO] Access token still valid for session 019c28c5-8655-74d1-9e57-2a132b1213cb (expires in 57 seconds)
|
||||||
|
13:09:29 [INFO] Access token still valid for session 019c28c5-8655-74d1-9e57-2a132b1213cb (expires in 50 seconds)
|
||||||
|
13:09:43 [INFO] Access token still valid for session 019c28c5-8655-74d1-9e57-2a132b1213cb (expires in 36 seconds)
|
||||||
|
13:10:09 [INFO] Callback called
|
||||||
|
13:10:09 [INFO] Successfully created session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 for user
|
||||||
|
13:10:09 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
13:10:10 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 59 seconds)
|
||||||
|
13:10:16 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 53 seconds)
|
||||||
|
13:16:18 [INFO] Access token expired for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959, attempting refresh
|
||||||
|
13:16:18 [INFO] Successfully refreshed access token for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959
|
||||||
|
13:16:21 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 57 seconds)
|
||||||
|
13:16:24 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 54 seconds)
|
||||||
|
13:16:31 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 47 seconds)
|
||||||
|
13:16:34 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 44 seconds)
|
||||||
|
13:16:38 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 40 seconds)
|
||||||
|
13:16:59 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 19 seconds)
|
||||||
|
13:17:01 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 17 seconds)
|
||||||
|
13:17:04 [INFO] Access token still valid for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959 (expires in 14 seconds)
|
||||||
|
14:02:29 [INFO] Access token expired for session 019c28c6-4b21-7541-b1ed-2ccc25ebe959, attempting refresh
|
||||||
|
14:02:29 [ERROR] Failed to refresh access token: Token refresh request failed: ServerResponse(StandardErrorResponse { error: invalid_grant, error_description: Some("Token is not active"), error_uri: None })
|
||||||
|
14:02:33 [WARN] Session not found in Redis: 019c28c6-4b21-7541-b1ed-2ccc25ebe959
|
||||||
|
14:02:39 [WARN] Session not found in Redis: 019c28c6-4b21-7541-b1ed-2ccc25ebe959
|
||||||
|
14:03:01 [WARN] Session not found in Redis: 019c28c6-4b21-7541-b1ed-2ccc25ebe959
|
||||||
|
14:03:05 [WARN] Session not found in Redis: 019c28c6-4b21-7541-b1ed-2ccc25ebe959
|
||||||
|
14:03:38 [INFO] Callback called
|
||||||
|
14:03:38 [INFO] Successfully created session 019c28f7-400a-7d22-8f5f-321b46c36a96 for user
|
||||||
|
14:03:38 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
14:03:38 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 60 seconds)
|
||||||
|
14:03:43 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 55 seconds)
|
||||||
|
14:03:49 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 49 seconds)
|
||||||
|
14:04:02 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 36 seconds)
|
||||||
|
14:04:05 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 33 seconds)
|
||||||
|
14:04:23 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 15 seconds)
|
||||||
|
14:04:29 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 9 seconds)
|
||||||
|
14:08:16 [INFO] Access token expired for session 019c28f7-400a-7d22-8f5f-321b46c36a96, attempting refresh
|
||||||
|
14:08:16 [INFO] Successfully refreshed access token for session 019c28f7-400a-7d22-8f5f-321b46c36a96
|
||||||
|
14:08:31 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 45 seconds)
|
||||||
|
14:08:35 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 41 seconds)
|
||||||
|
14:09:35 [INFO] Access token expired for session 019c28f7-400a-7d22-8f5f-321b46c36a96, attempting refresh
|
||||||
|
14:09:35 [INFO] Successfully refreshed access token for session 019c28f7-400a-7d22-8f5f-321b46c36a96
|
||||||
|
14:19:40 [INFO] Access token expired for session 019c28f7-400a-7d22-8f5f-321b46c36a96, attempting refresh
|
||||||
|
14:19:40 [INFO] Successfully refreshed access token for session 019c28f7-400a-7d22-8f5f-321b46c36a96
|
||||||
|
14:19:43 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 57 seconds)
|
||||||
|
14:19:46 [INFO] Access token still valid for session 019c28f7-400a-7d22-8f5f-321b46c36a96 (expires in 54 seconds)
|
||||||
|
14:21:54 [INFO] Access token expired for session 019c28f7-400a-7d22-8f5f-321b46c36a96, attempting refresh
|
||||||
|
14:21:54 [INFO] Successfully refreshed access token for session 019c28f7-400a-7d22-8f5f-321b46c36a96
|
||||||
|
14:23:04 [INFO] Callback called
|
||||||
|
14:23:04 [INFO] Successfully created session 019c2909-0a23-7910-b47d-229cb87792e1 for user
|
||||||
|
14:23:04 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
14:23:04 [INFO] Access token still valid for session 019c2909-0a23-7910-b47d-229cb87792e1 (expires in 60 seconds)
|
||||||
|
14:23:07 [INFO] Access token still valid for session 019c2909-0a23-7910-b47d-229cb87792e1 (expires in 57 seconds)
|
||||||
|
14:23:50 [INFO] Access token still valid for session 019c2909-0a23-7910-b47d-229cb87792e1 (expires in 14 seconds)
|
||||||
|
14:26:00 [INFO] Access token expired for session 019c2909-0a23-7910-b47d-229cb87792e1, attempting refresh
|
||||||
|
14:26:00 [INFO] Successfully refreshed access token for session 019c2909-0a23-7910-b47d-229cb87792e1
|
||||||
|
14:26:28 [INFO] Access token still valid for session 019c2909-0a23-7910-b47d-229cb87792e1 (expires in 32 seconds)
|
||||||
|
14:26:33 [INFO] Access token still valid for session 019c2909-0a23-7910-b47d-229cb87792e1 (expires in 27 seconds)
|
||||||
|
14:27:39 [INFO] Access token expired for session 019c2909-0a23-7910-b47d-229cb87792e1, attempting refresh
|
||||||
|
14:27:39 [INFO] Successfully refreshed access token for session 019c2909-0a23-7910-b47d-229cb87792e1
|
||||||
|
14:30:55 [INFO] Access token expired for session 019c2909-0a23-7910-b47d-229cb87792e1, attempting refresh
|
||||||
|
14:30:55 [INFO] Successfully refreshed access token for session 019c2909-0a23-7910-b47d-229cb87792e1
|
||||||
|
14:33:12 [INFO] Access token expired for session 019c2909-0a23-7910-b47d-229cb87792e1, attempting refresh
|
||||||
|
14:33:12 [INFO] Successfully refreshed access token for session 019c2909-0a23-7910-b47d-229cb87792e1
|
||||||
|
14:34:59 [INFO] Access token expired for session 019c2909-0a23-7910-b47d-229cb87792e1, attempting refresh
|
||||||
|
14:34:59 [INFO] Successfully refreshed access token for session 019c2909-0a23-7910-b47d-229cb87792e1
|
||||||
|
14:35:09 [INFO] Access token still valid for session 019c2909-0a23-7910-b47d-229cb87792e1 (expires in 50 seconds)
|
||||||
|
14:36:19 [INFO] Access token expired for session 019c2909-0a23-7910-b47d-229cb87792e1, attempting refresh
|
||||||
|
14:36:19 [INFO] Successfully refreshed access token for session 019c2909-0a23-7910-b47d-229cb87792e1
|
||||||
|
14:36:25 [INFO] Callback called
|
||||||
|
14:36:25 [INFO] Successfully created session 019c2915-43ab-77f0-8422-09f282747e59 for user
|
||||||
|
14:36:25 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
14:36:25 [INFO] Access token still valid for session 019c2915-43ab-77f0-8422-09f282747e59 (expires in 60 seconds)
|
||||||
|
14:36:27 [INFO] Access token still valid for session 019c2915-43ab-77f0-8422-09f282747e59 (expires in 58 seconds)
|
||||||
|
14:38:28 [INFO] Callback called
|
||||||
|
14:38:28 [INFO] Successfully created session 019c2917-2370-7f31-8a28-cec2911cc86d for user
|
||||||
|
14:38:28 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
14:38:28 [INFO] Access token still valid for session 019c2917-2370-7f31-8a28-cec2911cc86d (expires in 60 seconds)
|
||||||
|
14:38:30 [INFO] Access token still valid for session 019c2917-2370-7f31-8a28-cec2911cc86d (expires in 58 seconds)
|
||||||
|
14:39:35 [INFO] Callback called
|
||||||
|
14:39:35 [INFO] Successfully created session 019c2918-2b55-7002-8e53-12a8a5a0fdff for user
|
||||||
|
14:39:35 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
14:39:35 [INFO] Access token still valid for session 019c2918-2b55-7002-8e53-12a8a5a0fdff (expires in 60 seconds)
|
||||||
|
14:39:38 [INFO] Access token still valid for session 019c2918-2b55-7002-8e53-12a8a5a0fdff (expires in 57 seconds)
|
||||||
|
14:40:30 [INFO] Access token still valid for session 019c2918-2b55-7002-8e53-12a8a5a0fdff (expires in 5 seconds)
|
||||||
48
delivery_backend_2026-02-04T15-41-23.960899+0100.log
Normal file
48
delivery_backend_2026-02-04T15-41-23.960899+0100.log
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
14:41:23 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
14:41:23 [INFO] Logging initialized
|
||||||
|
14:41:23 [INFO] Starting Gas Delivery Backend
|
||||||
|
14:41:23 [INFO] Initializing redis server
|
||||||
|
14:41:23 [INFO] Starting axum server
|
||||||
|
14:41:23 [INFO] perform_oidc_discovery; kc_instance_id=019c2919-d1fa-7543-bd68-04be3e5bb6f5 kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
14:41:23 [INFO] Starting OIDC discovery.
|
||||||
|
14:41:23 [INFO] layer; id=019c2919-d1fb-7cd1-8431-b566c09b9235
|
||||||
|
14:41:23 [INFO] layer; id=019c2919-d1fb-7cd1-8431-b566c09b9235
|
||||||
|
14:41:23 [INFO] layer; id=019c2919-d1fb-7cd1-8431-b566c09b9235
|
||||||
|
14:41:23 [INFO] layer; id=019c2919-d1fb-7cd1-8431-b566c09b9235
|
||||||
|
14:41:23 [INFO] layer; id=019c2919-d1fb-7cd1-8431-b566c09b9235
|
||||||
|
14:41:23 [INFO] layer; id=019c2919-d1fb-7cd1-8431-b566c09b9235
|
||||||
|
14:41:23 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
14:41:24 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
14:41:30 [INFO] Access token expired for session 019c2918-2b55-7002-8e53-12a8a5a0fdff, attempting refresh
|
||||||
|
14:41:30 [INFO] Successfully refreshed access token for session 019c2918-2b55-7002-8e53-12a8a5a0fdff
|
||||||
|
14:50:01 [INFO] Access token expired for session 019c2918-2b55-7002-8e53-12a8a5a0fdff, attempting refresh
|
||||||
|
14:50:01 [INFO] Successfully refreshed access token for session 019c2918-2b55-7002-8e53-12a8a5a0fdff
|
||||||
|
15:03:17 [INFO] Access token expired for session 019c2918-2b55-7002-8e53-12a8a5a0fdff, attempting refresh
|
||||||
|
15:03:17 [INFO] Successfully refreshed access token for session 019c2918-2b55-7002-8e53-12a8a5a0fdff
|
||||||
|
15:32:24 [INFO] Access token expired for session 019c2918-2b55-7002-8e53-12a8a5a0fdff, attempting refresh
|
||||||
|
15:32:25 [INFO] Successfully refreshed access token for session 019c2918-2b55-7002-8e53-12a8a5a0fdff
|
||||||
|
15:34:19 [INFO] Callback called
|
||||||
|
15:34:19 [INFO] Successfully created session 019c294a-4604-7e01-bc3a-aee67bb365fb for user
|
||||||
|
15:34:19 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
15:34:19 [INFO] Access token still valid for session 019c294a-4604-7e01-bc3a-aee67bb365fb (expires in 60 seconds)
|
||||||
|
15:36:08 [INFO] Callback called
|
||||||
|
15:36:08 [INFO] Successfully created session 019c294b-eee5-72e1-a80e-b7e03b2e5877 for user
|
||||||
|
15:36:08 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
15:36:08 [INFO] Access token still valid for session 019c294b-eee5-72e1-a80e-b7e03b2e5877 (expires in 60 seconds)
|
||||||
|
15:36:53 [INFO] Callback called
|
||||||
|
15:36:53 [INFO] Successfully created session 019c294c-a034-7420-9a1e-8351aa3b457c for user
|
||||||
|
15:36:53 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
15:36:53 [INFO] Access token still valid for session 019c294c-a034-7420-9a1e-8351aa3b457c (expires in 60 seconds)
|
||||||
|
15:37:02 [INFO] Callback called
|
||||||
|
15:37:02 [INFO] Successfully created session 019c294c-c1a7-7402-9415-f0bd5b86b032 for user
|
||||||
|
15:37:02 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
15:37:02 [INFO] Access token still valid for session 019c294c-c1a7-7402-9415-f0bd5b86b032 (expires in 60 seconds)
|
||||||
|
15:37:43 [INFO] Callback called
|
||||||
|
15:37:43 [INFO] Successfully created session 019c294d-6384-7c03-af9f-000ce003bff6 for user
|
||||||
|
15:37:43 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
15:37:43 [INFO] Access token still valid for session 019c294d-6384-7c03-af9f-000ce003bff6 (expires in 60 seconds)
|
||||||
|
15:39:07 [INFO] Callback called
|
||||||
|
15:39:07 [INFO] Successfully created session 019c294e-aa9e-70e1-b059-38e2297ca892 for user
|
||||||
|
15:39:07 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
15:39:07 [INFO] Access token still valid for session 019c294e-aa9e-70e1-b059-38e2297ca892 (expires in 60 seconds)
|
||||||
|
15:39:09 [INFO] Access token still valid for session 019c294e-aa9e-70e1-b059-38e2297ca892 (expires in 58 seconds)
|
||||||
89
delivery_backend_2026-02-04T16-40-54.682126+0100.log
Normal file
89
delivery_backend_2026-02-04T16-40-54.682126+0100.log
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
15:40:54 [INFO] Redirect URI: http://127.0.0.1:3000/callback
|
||||||
|
15:40:54 [INFO] Logging initialized
|
||||||
|
15:40:54 [INFO] Starting Gas Delivery Backend
|
||||||
|
15:40:54 [INFO] Initializing redis server
|
||||||
|
15:40:54 [INFO] Starting axum server
|
||||||
|
15:40:54 [INFO] perform_oidc_discovery; kc_instance_id=019c2950-4e1c-76f0-b16d-3eec0bc754be kc_server="http://127.0.0.1:8080/" kc_realm="master" oidc_discovery_endpoint="http://127.0.0.1:8080/realms/master/.well-known/openid-configuration"
|
||||||
|
15:40:54 [INFO] Starting OIDC discovery.
|
||||||
|
15:40:54 [INFO] layer; id=019c2950-4e1c-76f0-b16d-3ef3197d32e0
|
||||||
|
15:40:54 [INFO] layer; id=019c2950-4e1c-76f0-b16d-3ef3197d32e0
|
||||||
|
15:40:54 [INFO] layer; id=019c2950-4e1c-76f0-b16d-3ef3197d32e0
|
||||||
|
15:40:54 [INFO] layer; id=019c2950-4e1c-76f0-b16d-3ef3197d32e0
|
||||||
|
15:40:54 [INFO] layer; id=019c2950-4e1c-76f0-b16d-3ef3197d32e0
|
||||||
|
15:40:54 [INFO] layer; id=019c2950-4e1c-76f0-b16d-3ef3197d32e0
|
||||||
|
15:40:54 [INFO] Listening on 127.0.0.1:3000
|
||||||
|
15:40:54 [INFO] Received new jwk_set containing 2 keys.
|
||||||
|
15:41:03 [INFO] Callback called
|
||||||
|
15:41:03 [INFO] Successfully created session 019c2950-70b1-7b10-8a55-3c9ada4d8864 for user
|
||||||
|
15:41:03 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
15:41:03 [INFO] Access token still valid for session 019c2950-70b1-7b10-8a55-3c9ada4d8864 (expires in 60 seconds)
|
||||||
|
15:41:05 [INFO] Access token still valid for session 019c2950-70b1-7b10-8a55-3c9ada4d8864 (expires in 58 seconds)
|
||||||
|
15:41:46 [INFO] Access token still valid for session 019c2950-70b1-7b10-8a55-3c9ada4d8864 (expires in 17 seconds)
|
||||||
|
15:46:12 [INFO] Access token expired for session 019c2950-70b1-7b10-8a55-3c9ada4d8864, attempting refresh
|
||||||
|
15:46:12 [INFO] Successfully refreshed access token for session 019c2950-70b1-7b10-8a55-3c9ada4d8864
|
||||||
|
15:46:23 [INFO] Access token still valid for session 019c2950-70b1-7b10-8a55-3c9ada4d8864 (expires in 49 seconds)
|
||||||
|
15:46:39 [INFO] Access token still valid for session 019c2950-70b1-7b10-8a55-3c9ada4d8864 (expires in 33 seconds)
|
||||||
|
15:47:57 [INFO] Access token expired for session 019c2950-70b1-7b10-8a55-3c9ada4d8864, attempting refresh
|
||||||
|
15:47:57 [INFO] Successfully refreshed access token for session 019c2950-70b1-7b10-8a55-3c9ada4d8864
|
||||||
|
15:58:54 [INFO] Callback called
|
||||||
|
15:58:54 [INFO] Successfully created session 019c2960-c909-7ad2-aa9a-e6286fb8a38d for user
|
||||||
|
15:58:54 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
15:58:54 [INFO] Access token still valid for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d (expires in 60 seconds)
|
||||||
|
15:58:57 [INFO] Access token still valid for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d (expires in 57 seconds)
|
||||||
|
16:03:13 [INFO] Access token expired for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d, attempting refresh
|
||||||
|
16:03:13 [INFO] Successfully refreshed access token for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d
|
||||||
|
16:03:19 [INFO] Access token still valid for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d (expires in 54 seconds)
|
||||||
|
16:04:56 [INFO] Access token expired for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d, attempting refresh
|
||||||
|
16:04:56 [INFO] Successfully refreshed access token for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d
|
||||||
|
16:14:40 [INFO] Access token expired for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d, attempting refresh
|
||||||
|
16:14:40 [INFO] Successfully refreshed access token for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d
|
||||||
|
16:32:07 [INFO] Access token expired for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d, attempting refresh
|
||||||
|
16:32:07 [INFO] Successfully refreshed access token for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d
|
||||||
|
16:34:48 [INFO] Access token expired for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d, attempting refresh
|
||||||
|
16:34:48 [INFO] Successfully refreshed access token for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d
|
||||||
|
16:46:07 [INFO] Access token expired for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d, attempting refresh
|
||||||
|
16:46:07 [INFO] Successfully refreshed access token for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d
|
||||||
|
16:46:28 [INFO] Access token still valid for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d (expires in 39 seconds)
|
||||||
|
16:46:34 [INFO] Access token still valid for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d (expires in 33 seconds)
|
||||||
|
16:46:54 [INFO] Access token still valid for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d (expires in 13 seconds)
|
||||||
|
16:47:46 [INFO] Access token expired for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d, attempting refresh
|
||||||
|
16:47:46 [INFO] Successfully refreshed access token for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d
|
||||||
|
16:48:50 [INFO] Access token expired for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d, attempting refresh
|
||||||
|
16:48:50 [INFO] Successfully refreshed access token for session 019c2960-c909-7ad2-aa9a-e6286fb8a38d
|
||||||
|
16:53:28 [INFO] Callback called
|
||||||
|
16:53:28 [INFO] Successfully created session 019c2992-bbbe-7a31-9c39-d24a9af89e59 for user
|
||||||
|
16:53:28 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
16:53:28 [INFO] Access token still valid for session 019c2992-bbbe-7a31-9c39-d24a9af89e59 (expires in 60 seconds)
|
||||||
|
16:53:31 [INFO] Access token still valid for session 019c2992-bbbe-7a31-9c39-d24a9af89e59 (expires in 57 seconds)
|
||||||
|
16:55:06 [INFO] Access token expired for session 019c2992-bbbe-7a31-9c39-d24a9af89e59, attempting refresh
|
||||||
|
16:55:06 [INFO] Successfully refreshed access token for session 019c2992-bbbe-7a31-9c39-d24a9af89e59
|
||||||
|
16:55:41 [INFO] Access token still valid for session 019c2992-bbbe-7a31-9c39-d24a9af89e59 (expires in 25 seconds)
|
||||||
|
16:56:19 [INFO] Access token expired for session 019c2992-bbbe-7a31-9c39-d24a9af89e59, attempting refresh
|
||||||
|
16:56:19 [INFO] Successfully refreshed access token for session 019c2992-bbbe-7a31-9c39-d24a9af89e59
|
||||||
|
16:56:27 [INFO] Access token still valid for session 019c2992-bbbe-7a31-9c39-d24a9af89e59 (expires in 52 seconds)
|
||||||
|
16:57:59 [INFO] Access token expired for session 019c2992-bbbe-7a31-9c39-d24a9af89e59, attempting refresh
|
||||||
|
16:57:59 [INFO] Successfully refreshed access token for session 019c2992-bbbe-7a31-9c39-d24a9af89e59
|
||||||
|
17:00:14 [INFO] Access token expired for session 019c2992-bbbe-7a31-9c39-d24a9af89e59, attempting refresh
|
||||||
|
17:00:14 [INFO] Successfully refreshed access token for session 019c2992-bbbe-7a31-9c39-d24a9af89e59
|
||||||
|
17:02:17 [INFO] Access token expired for session 019c2992-bbbe-7a31-9c39-d24a9af89e59, attempting refresh
|
||||||
|
17:02:17 [INFO] Successfully refreshed access token for session 019c2992-bbbe-7a31-9c39-d24a9af89e59
|
||||||
|
17:04:48 [INFO] Access token expired for session 019c2992-bbbe-7a31-9c39-d24a9af89e59, attempting refresh
|
||||||
|
17:04:48 [INFO] Successfully refreshed access token for session 019c2992-bbbe-7a31-9c39-d24a9af89e59
|
||||||
|
17:07:53 [INFO] Access token expired for session 019c2992-bbbe-7a31-9c39-d24a9af89e59, attempting refresh
|
||||||
|
17:07:53 [INFO] Successfully refreshed access token for session 019c2992-bbbe-7a31-9c39-d24a9af89e59
|
||||||
|
17:08:18 [INFO] Callback called
|
||||||
|
17:08:18 [INFO] Successfully created session 019c29a0-50f3-7871-bf39-41d1657b14cc for user
|
||||||
|
17:08:18 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
17:08:18 [INFO] Access token still valid for session 019c29a0-50f3-7871-bf39-41d1657b14cc (expires in 60 seconds)
|
||||||
|
17:08:20 [INFO] Access token still valid for session 019c29a0-50f3-7871-bf39-41d1657b14cc (expires in 58 seconds)
|
||||||
|
17:08:22 [INFO] Access token still valid for session 019c29a0-50f3-7871-bf39-41d1657b14cc (expires in 56 seconds)
|
||||||
|
18:56:26 [INFO] Access token expired for session 019c29a0-50f3-7871-bf39-41d1657b14cc, attempting refresh
|
||||||
|
18:56:26 [ERROR] Failed to refresh access token: Token refresh request failed: ServerResponse(StandardErrorResponse { error: invalid_grant, error_description: Some("Token is not active"), error_uri: None })
|
||||||
|
19:41:28 [WARN] Session not found in Redis: 019c29a0-50f3-7871-bf39-41d1657b14cc
|
||||||
|
19:41:45 [INFO] Callback called
|
||||||
|
19:41:45 [INFO] Successfully created session 019c2a2c-cfde-70a3-98ae-861a5a55cd64 for user
|
||||||
|
19:41:45 [INFO] Token scopes: EmptyExtraTokenFields
|
||||||
|
19:41:46 [INFO] Access token still valid for session 019c2a2c-cfde-70a3-98ae-861a5a55cd64 (expires in 59 seconds)
|
||||||
|
19:41:51 [INFO] Access token still valid for session 019c2a2c-cfde-70a3-98ae-861a5a55cd64 (expires in 54 seconds)
|
||||||
|
19:54:01 [INFO] Access token expired for session 019c2a2c-cfde-70a3-98ae-861a5a55cd64, attempting refresh
|
||||||
|
19:54:01 [INFO] Successfully refreshed access token for session 019c2a2c-cfde-70a3-98ae-861a5a55cd64
|
||||||
77
docker-compose.yaml
Normal file
77
docker-compose.yaml
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: redis-server
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# microservice:
|
||||||
|
# build:
|
||||||
|
# context: .
|
||||||
|
# dockerfile: Dockerfile
|
||||||
|
# container_name: rust-microservice
|
||||||
|
# ports:
|
||||||
|
# - "3000:3000"
|
||||||
|
# environment:
|
||||||
|
# - REDIS_URL=redis://redis:6379
|
||||||
|
# - RUST_LOG=info
|
||||||
|
# depends_on:
|
||||||
|
# redis:
|
||||||
|
# condition: service_healthy
|
||||||
|
# networks:
|
||||||
|
# - app-network
|
||||||
|
# restart: unless-stopped
|
||||||
|
|
||||||
|
keycloak_web:
|
||||||
|
image: quay.io/keycloak/keycloak:23.0.7
|
||||||
|
container_name: keycloak_web
|
||||||
|
environment:
|
||||||
|
KC_DB: postgres
|
||||||
|
KC_DB_URL: jdbc:postgresql://keycloakdb:5432/keycloak
|
||||||
|
KC_DB_USERNAME: ${POSTGRES_USER}
|
||||||
|
KC_DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
|
||||||
|
KC_HOSTNAME: 127.0.0.1
|
||||||
|
KC_HOSTNAME_PORT: 8080
|
||||||
|
KC_HOSTNAME_STRICT: false
|
||||||
|
KC_HOSTNAME_STRICT_HTTPS: false
|
||||||
|
|
||||||
|
KC_LOG_LEVEL: info
|
||||||
|
KC_METRICS_ENABLED: true
|
||||||
|
KC_HEALTH_ENABLED: true
|
||||||
|
KEYCLOAK_ADMIN: admin
|
||||||
|
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
|
||||||
|
command: start-dev
|
||||||
|
depends_on:
|
||||||
|
- keycloakdb
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
|
||||||
|
keycloakdb:
|
||||||
|
image: postgres:15
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: keycloak
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis-data:
|
||||||
|
driver: local
|
||||||
|
postgres_data:
|
||||||
|
driver: local
|
||||||
2
requests/get_cars_by_supplier.http
Normal file
2
requests/get_cars_by_supplier.http
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
GET http://127.0.0.1:3000/cars
|
||||||
|
Cookie: session_id=019c28ac-2f5a-75e1-b909-f862e773a5c6
|
||||||
2
requests/get_tour_by_car.http
Normal file
2
requests/get_tour_by_car.http
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
GET http://127.0.0.1:3000/tour/1234
|
||||||
|
Cookie: session_id=019c28ac-2f5a-75e1-b909-f862e773a5c6
|
||||||
5
requests/http-client.private.env.json
Normal file
5
requests/http-client.private.env.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dev": {
|
||||||
|
"supplier_id": "12345"
|
||||||
|
}
|
||||||
|
}
|
||||||
4
requests/userinfo.http
Normal file
4
requests/userinfo.http
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
### GET request to example server
|
||||||
|
GET http://127.0.0.1:3000/userinfo
|
||||||
|
Cookie: session_id=019c22f6-d203-7ff2-b80c-c13ce9b84b69
|
||||||
|
###
|
||||||
16
src/api.rs
Normal file
16
src/api.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
pub(crate) mod supplier;
|
||||||
|
pub(crate) mod tour;
|
||||||
|
|
||||||
|
use crate::util::{decode_payload_unchecked};
|
||||||
|
use axum::body::Body;
|
||||||
|
use axum::extract::Request;
|
||||||
|
use axum::response::IntoResponse;
|
||||||
|
use crate::model::{User};
|
||||||
|
|
||||||
|
pub async fn userinfo(request: Request<Body>) -> impl IntoResponse {
|
||||||
|
let access_token_string = &request.headers().get("authorization").unwrap().to_str().unwrap().to_string()[7..];
|
||||||
|
println!("access_token_string is {}", access_token_string);
|
||||||
|
let user = decode_payload_unchecked::<User>(access_token_string).unwrap();
|
||||||
|
|
||||||
|
serde_json::to_string(&user.employee).unwrap().into_response()
|
||||||
|
}
|
||||||
27
src/api/supplier.rs
Normal file
27
src/api/supplier.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use crate::dto::{GetCarInfosDTO, get_example_deliveries};
|
||||||
|
use crate::model::User;
|
||||||
|
use crate::response::{FailResponse, ResponseFactory};
|
||||||
|
use crate::util::decode_payload_unchecked;
|
||||||
|
use axum::Json;
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum_extra::TypedHeader;
|
||||||
|
use axum_extra::headers::Authorization;
|
||||||
|
use axum_extra::headers::authorization::Bearer;
|
||||||
|
|
||||||
|
pub async fn load_supplier_cars(
|
||||||
|
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||||
|
) -> Result<Json<GetCarInfosDTO>, (StatusCode, Json<FailResponse>)> {
|
||||||
|
let user_res = decode_payload_unchecked::<User>(auth.token());
|
||||||
|
|
||||||
|
if let Err(e) = user_res {
|
||||||
|
return Err((
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
Json(ResponseFactory::error(
|
||||||
|
format!("An error occured: {}", e.to_string()),
|
||||||
|
Some(StatusCode::UNAUTHORIZED.as_u16() as u32),
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Json(get_example_deliveries()))
|
||||||
|
}
|
||||||
29
src/api/tour.rs
Normal file
29
src/api/tour.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use axum::extract::Path;
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum::Json;
|
||||||
|
use axum_extra::headers::Authorization;
|
||||||
|
use axum_extra::headers::authorization::Bearer;
|
||||||
|
use axum_extra::TypedHeader;
|
||||||
|
use crate::dto::{get_example_deliveries, get_test_tour, GetCarInfosDTO, TourDTO};
|
||||||
|
use crate::model::User;
|
||||||
|
use crate::response::{FailResponse, ResponseFactory};
|
||||||
|
use crate::util::decode_payload_unchecked;
|
||||||
|
|
||||||
|
pub async fn load_tour(
|
||||||
|
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||||
|
Path(car_id): Path<u64>
|
||||||
|
) -> Result<Json<TourDTO>, (StatusCode, Json<FailResponse>)> {
|
||||||
|
let user_res = decode_payload_unchecked::<User>(auth.token());
|
||||||
|
|
||||||
|
if let Err(e) = user_res {
|
||||||
|
return Err((
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
Json(ResponseFactory::error(
|
||||||
|
format!("An error occured: {}", e.to_string()),
|
||||||
|
Some(StatusCode::UNAUTHORIZED.as_u16() as u32),
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Json(get_test_tour(car_id)))
|
||||||
|
}
|
||||||
425
src/auth.rs
Normal file
425
src/auth.rs
Normal file
@ -0,0 +1,425 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::middleware::AppState;
|
||||||
|
use crate::repository::RedisRepository;
|
||||||
|
use axum::http::{StatusCode, header};
|
||||||
|
use axum::response::{Html, Response};
|
||||||
|
use axum::{
|
||||||
|
Router,
|
||||||
|
extract::{Query, State},
|
||||||
|
response::{IntoResponse, Redirect},
|
||||||
|
routing::get,
|
||||||
|
};
|
||||||
|
use axum_extra::extract::CookieJar;
|
||||||
|
use oauth2::basic::{
|
||||||
|
BasicErrorResponse, BasicRevocationErrorResponse, BasicTokenIntrospectionResponse,
|
||||||
|
BasicTokenResponse,
|
||||||
|
};
|
||||||
|
use oauth2::{
|
||||||
|
AuthUrl, AuthorizationCode, Client, ClientId, ClientSecret, CsrfToken, EndpointNotSet,
|
||||||
|
EndpointSet, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, Scope, StandardRevocableToken,
|
||||||
|
TokenResponse, TokenUrl, basic::BasicClient,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use axum::routing::post;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
pub type OAuthClient = Client<
|
||||||
|
BasicErrorResponse,
|
||||||
|
BasicTokenResponse,
|
||||||
|
BasicTokenIntrospectionResponse,
|
||||||
|
StandardRevocableToken,
|
||||||
|
BasicRevocationErrorResponse,
|
||||||
|
EndpointSet,
|
||||||
|
EndpointNotSet,
|
||||||
|
EndpointNotSet,
|
||||||
|
EndpointNotSet,
|
||||||
|
EndpointSet,
|
||||||
|
>;
|
||||||
|
|
||||||
|
pub fn router(state: Arc<AppState>) -> Router {
|
||||||
|
Router::new()
|
||||||
|
.route("/login", get(login))
|
||||||
|
.route("/callback", get(callback))
|
||||||
|
.route("/logout", post(logout))
|
||||||
|
.with_state(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn login(State(client): State<Arc<AppState>>) -> impl IntoResponse {
|
||||||
|
let cloned_client = client.clone();
|
||||||
|
let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
|
||||||
|
let csrf_token = CsrfToken::new_random();
|
||||||
|
|
||||||
|
// Store the PKCE verifier in Redis with CSRF token as key
|
||||||
|
let redis_key = format!("pkce_verifier:{}", csrf_token.secret());
|
||||||
|
let verifier_secret = pkce_verifier.secret().to_string();
|
||||||
|
|
||||||
|
match cloned_client
|
||||||
|
.repository
|
||||||
|
.set_with_expiry(&redis_key, &verifier_secret, 600) // 10 minutes expiry
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {
|
||||||
|
let (auth_url, _) = cloned_client
|
||||||
|
.oauth_client
|
||||||
|
.authorize_url(|| csrf_token)
|
||||||
|
.add_scope(Scope::new("openid".to_string()))
|
||||||
|
.add_scope(Scope::new("profile".to_string()))
|
||||||
|
.add_scope(Scope::new("email".to_string()))
|
||||||
|
.set_pkce_challenge(pkce_challenge)
|
||||||
|
.url();
|
||||||
|
|
||||||
|
Redirect::to(auth_url.as_str()).into_response()
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to store PKCE verifier in Redis: {:?}", e);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"Failed to initiate login",
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Callback {
|
||||||
|
code: String,
|
||||||
|
state: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct UserSession {
|
||||||
|
pub(crate) access_token: String,
|
||||||
|
pub(crate) refresh_token: String,
|
||||||
|
pub(crate) expires_at: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn callback(
|
||||||
|
State(client): State<Arc<AppState>>,
|
||||||
|
Query(query): Query<Callback>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let http_client = reqwest::ClientBuilder::new()
|
||||||
|
.redirect(reqwest::redirect::Policy::none())
|
||||||
|
.build()
|
||||||
|
.expect("Client should build");
|
||||||
|
|
||||||
|
let cloned_state = client.clone();
|
||||||
|
|
||||||
|
log::info!("Callback called");
|
||||||
|
|
||||||
|
// Retrieve the PKCE verifier from Redis using CSRF token
|
||||||
|
let redis_key = format!("pkce_verifier:{}", query.state);
|
||||||
|
|
||||||
|
let verifier_secret = match cloned_state.repository.get(&redis_key).await {
|
||||||
|
Ok(Some(secret)) => secret,
|
||||||
|
Ok(None) => {
|
||||||
|
log::error!("PKCE verifier not found for state: {}", query.state);
|
||||||
|
return (
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
"Invalid or expired login session. Please try again.",
|
||||||
|
)
|
||||||
|
.into_response();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to retrieve PKCE verifier from Redis: {:?}", e);
|
||||||
|
return (StatusCode::INTERNAL_SERVER_ERROR, "Login failed").into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete the verifier from Redis (one-time use)
|
||||||
|
let _ = cloned_state.repository.delete(&redis_key).await;
|
||||||
|
let pkce_verifier = PkceCodeVerifier::new(verifier_secret);
|
||||||
|
|
||||||
|
let token_result = cloned_state
|
||||||
|
.oauth_client
|
||||||
|
.exchange_code(AuthorizationCode::new(query.code))
|
||||||
|
.set_pkce_verifier(pkce_verifier)
|
||||||
|
.request_async(&http_client)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match token_result {
|
||||||
|
Ok(token) => {
|
||||||
|
let access_token = token.access_token().secret();
|
||||||
|
let refresh_token = token
|
||||||
|
.refresh_token()
|
||||||
|
.map(|rt| rt.secret().to_string())
|
||||||
|
.unwrap_or_else(|| "No refresh token".to_string());
|
||||||
|
|
||||||
|
let expires_at = chrono::Utc::now().timestamp()
|
||||||
|
+ token
|
||||||
|
.expires_in()
|
||||||
|
.map(|d| d.as_secs() as i64)
|
||||||
|
.unwrap_or(3600);
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// 1. GENERATE A UNIQUE SESSION ID
|
||||||
|
// ============================================
|
||||||
|
let session_id = uuid::Uuid::now_v7().to_string();
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// 2. CREATE THE USER SESSION STRUCT
|
||||||
|
// ============================================
|
||||||
|
let user_session = UserSession {
|
||||||
|
access_token: access_token.clone(),
|
||||||
|
refresh_token: refresh_token.clone(),
|
||||||
|
expires_at,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// 3. SERIALIZE THE SESSION TO JSON
|
||||||
|
// ============================================
|
||||||
|
let session_key = format!("user_session:{}", session_id);
|
||||||
|
let session_json = match serde_json::to_string(&user_session) {
|
||||||
|
Ok(json) => json,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to serialize user session: {:?}", e);
|
||||||
|
return (StatusCode::INTERNAL_SERVER_ERROR, "Login failed").into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// 4. STORE IN REDIS WITH 24 HOUR EXPIRATION
|
||||||
|
// This is where the tokens are actually stored!
|
||||||
|
// ============================================
|
||||||
|
if let Err(e) = cloned_state
|
||||||
|
.repository
|
||||||
|
.set_with_expiry(&session_key, &session_json, 86400) // 86400 = 24 hours
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log::error!("Failed to store user session in Redis: {:?}", e);
|
||||||
|
return (StatusCode::INTERNAL_SERVER_ERROR, "Login failed").into_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Successfully created session {} for user", session_id);
|
||||||
|
info!("Token scopes: {:?}", token.extra_fields());
|
||||||
|
|
||||||
|
// 4. Redirect to frontend
|
||||||
|
let redirect_url = format!("{}/?session_id={}", cloned_state.frontend_url.clone(), session_id);
|
||||||
|
|
||||||
|
Redirect::to(redirect_url.as_str()).into_response()
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Token exchange failed: {:?}", e);
|
||||||
|
(StatusCode::UNAUTHORIZED, format!("Login failed: {:?}", e)).into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_oauth_client(config: &Config) -> OAuthClient {
|
||||||
|
BasicClient::new(ClientId::new(config.keycloak.client_id.clone()))
|
||||||
|
.set_client_secret(ClientSecret::new(config.keycloak.client_secret.clone()))
|
||||||
|
.set_redirect_uri(RedirectUrl::new(config.keycloak.redirect_url.clone()).unwrap())
|
||||||
|
.set_token_uri(TokenUrl::new(config.keycloak.token_url.clone()).unwrap())
|
||||||
|
.set_auth_uri(AuthUrl::new(config.keycloak.auth_url.clone()).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal helper to refresh access token
|
||||||
|
pub async fn refresh_access_token_internal(
|
||||||
|
client: &OAuthClient,
|
||||||
|
repository: &RedisRepository,
|
||||||
|
session_id: &str,
|
||||||
|
user_session: &mut UserSession,
|
||||||
|
) -> Result<String, String> {
|
||||||
|
use oauth2::{RefreshToken, TokenResponse};
|
||||||
|
|
||||||
|
let http_client = reqwest::ClientBuilder::new()
|
||||||
|
.redirect(reqwest::redirect::Policy::none())
|
||||||
|
.build()
|
||||||
|
.expect("Client should build");
|
||||||
|
|
||||||
|
let refresh_token = &user_session.refresh_token;
|
||||||
|
|
||||||
|
// Exchange refresh token for new access token
|
||||||
|
let token_result = client
|
||||||
|
.exchange_refresh_token(&RefreshToken::new(refresh_token.clone()))
|
||||||
|
.request_async(&http_client)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Token refresh request failed: {:?}", e))?;
|
||||||
|
|
||||||
|
// Update session with new tokens
|
||||||
|
let new_access_token = token_result.access_token().secret().to_string();
|
||||||
|
user_session.access_token = new_access_token.clone();
|
||||||
|
|
||||||
|
// Update refresh token if a new one was provided
|
||||||
|
if let Some(new_refresh_token) = token_result.refresh_token() {
|
||||||
|
user_session.refresh_token = new_refresh_token.secret().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update expiration time
|
||||||
|
user_session.expires_at = chrono::Utc::now().timestamp()
|
||||||
|
+ token_result
|
||||||
|
.expires_in()
|
||||||
|
.map(|d| d.as_secs() as i64)
|
||||||
|
.unwrap_or(3600);
|
||||||
|
|
||||||
|
// Save updated session back to Redis
|
||||||
|
let session_key = format!("user_session:{}", session_id);
|
||||||
|
let updated_json = serde_json::to_string(&user_session)
|
||||||
|
.map_err(|e| format!("Failed to serialize session: {:?}", e))?;
|
||||||
|
|
||||||
|
repository
|
||||||
|
.set_with_expiry(&session_key, &updated_json, 86400)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to update session in Redis: {:?}", e))?;
|
||||||
|
|
||||||
|
Ok(new_access_token)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn logout(jar: CookieJar, State(oauth_state): State<Arc<AppState>>) -> impl IntoResponse {
|
||||||
|
// 1. Extract session ID from cookie
|
||||||
|
let session_id = match jar.get("session_id") {
|
||||||
|
Some(cookie) => cookie.value().to_string(),
|
||||||
|
None => {
|
||||||
|
log::warn!("Logout attempted without session cookie");
|
||||||
|
return (StatusCode::BAD_REQUEST, "No active session").into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Get session from Redis to retrieve tokens
|
||||||
|
let session_key = format!("user_session:{}", session_id);
|
||||||
|
let session_json = match oauth_state.repository.get(&session_key).await {
|
||||||
|
Ok(Some(json)) => json,
|
||||||
|
Ok(None) => {
|
||||||
|
log::warn!("Session not found in Redis: {}", session_id);
|
||||||
|
// Session already gone, just clear cookie
|
||||||
|
return clear_session_cookie().into_response();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Redis error while fetching session for logout: {:?}", e);
|
||||||
|
return (StatusCode::INTERNAL_SERVER_ERROR, "Logout failed").into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_session: UserSession = match serde_json::from_str(&session_json) {
|
||||||
|
Ok(session) => session,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to parse session JSON during logout: {:?}", e);
|
||||||
|
// Clean up anyway
|
||||||
|
let _ = oauth_state.repository.delete(&session_key).await;
|
||||||
|
return clear_session_cookie().into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 3. Revoke tokens at Keycloak
|
||||||
|
let revoke_result = revoke_tokens_at_keycloak(
|
||||||
|
&oauth_state,
|
||||||
|
&user_session.access_token,
|
||||||
|
&user_session.refresh_token,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(e) = revoke_result {
|
||||||
|
log::error!("Failed to revoke tokens at Keycloak: {}", e);
|
||||||
|
// Continue anyway - we'll still delete local session
|
||||||
|
} else {
|
||||||
|
log::info!(
|
||||||
|
"Successfully revoked tokens at Keycloak for session {}",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Delete session from Redis
|
||||||
|
match oauth_state.repository.delete(&session_key).await {
|
||||||
|
Ok(_) => {
|
||||||
|
log::info!("Successfully deleted session {} from Redis", session_id);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to delete session from Redis: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Clear session cookie and respond
|
||||||
|
clear_session_cookie().into_response()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to revoke tokens at Keycloak's revocation endpoint
|
||||||
|
async fn revoke_tokens_at_keycloak(
|
||||||
|
oauth_state: &Arc<AppState>,
|
||||||
|
access_token: &str,
|
||||||
|
refresh_token: &str,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
// Get client credentials from OAuth client
|
||||||
|
let client_id = oauth_state.oauth_client.client_id().as_str();
|
||||||
|
let client_secret = oauth_state.config.keycloak.client_secret.as_str();
|
||||||
|
|
||||||
|
// Build revocation endpoint URL
|
||||||
|
// Keycloak's revocation endpoint is typically at:
|
||||||
|
// {realm_url}/protocol/openid-connect/revoke
|
||||||
|
let token_url = oauth_state.config.keycloak.token_url.as_str();
|
||||||
|
|
||||||
|
// Replace /token with /revoke
|
||||||
|
let revoke_url = token_url.replace("/token", "/revoke");
|
||||||
|
|
||||||
|
log::info!("Revoking tokens at: {}", revoke_url);
|
||||||
|
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
// Revoke refresh token (this also invalidates the access token)
|
||||||
|
let revoke_refresh_result = client
|
||||||
|
.post(&revoke_url)
|
||||||
|
.form(&[
|
||||||
|
("token", refresh_token),
|
||||||
|
("token_type_hint", "refresh_token"),
|
||||||
|
("client_id", client_id),
|
||||||
|
("client_secret", client_secret),
|
||||||
|
])
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to send revoke request: {:?}", e))?;
|
||||||
|
|
||||||
|
if !revoke_refresh_result.status().is_success() {
|
||||||
|
let status = revoke_refresh_result.status();
|
||||||
|
let body = revoke_refresh_result
|
||||||
|
.text()
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|_| "Unable to read response".to_string());
|
||||||
|
log::warn!(
|
||||||
|
"Token revocation returned non-success status {}: {}",
|
||||||
|
status,
|
||||||
|
body
|
||||||
|
);
|
||||||
|
// Note: Keycloak returns 200 even if token is already invalid, so this is unusual
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionally also revoke access token explicitly
|
||||||
|
let revoke_access_result = client
|
||||||
|
.post(&revoke_url)
|
||||||
|
.form(&[
|
||||||
|
("token", access_token),
|
||||||
|
("token_type_hint", "access_token"),
|
||||||
|
("client_id", client_id),
|
||||||
|
("client_secret", client_secret),
|
||||||
|
])
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to send revoke request for access token: {:?}", e))?;
|
||||||
|
|
||||||
|
if !revoke_access_result.status().is_success() {
|
||||||
|
let status = revoke_access_result.status();
|
||||||
|
let body = revoke_access_result
|
||||||
|
.text()
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|_| "Unable to read response".to_string());
|
||||||
|
log::warn!(
|
||||||
|
"Access token revocation returned non-success status {}: {}",
|
||||||
|
status,
|
||||||
|
body
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to create a response that clears the session cookie
|
||||||
|
fn clear_session_cookie() -> Response {
|
||||||
|
// Set cookie with Max-Age=0 to delete it
|
||||||
|
let clear_cookie = "session_id=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0";
|
||||||
|
|
||||||
|
Response::builder()
|
||||||
|
.status(StatusCode::OK)
|
||||||
|
.header(header::SET_COOKIE, clear_cookie)
|
||||||
|
.body("Logged out successfully".into())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
97
src/config.rs
Normal file
97
src/config.rs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
const CONFIG_FILE: &str = "config.toml";
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Clone)]
|
||||||
|
pub struct Config {
|
||||||
|
// Backend server configuration
|
||||||
|
pub log_file_prefix: String,
|
||||||
|
pub host_ip: String,
|
||||||
|
pub host_port: u16,
|
||||||
|
pub redis_url: String,
|
||||||
|
|
||||||
|
pub frontend_url: String,
|
||||||
|
|
||||||
|
// GSD RestAPI configuration
|
||||||
|
pub gsd_app_key: String,
|
||||||
|
pub gsd_rest_url: String,
|
||||||
|
pub gsd_user: String,
|
||||||
|
pub gsd_password: String,
|
||||||
|
pub gsd_app_names: Vec<String>,
|
||||||
|
|
||||||
|
pub keycloak: Keycloak,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Clone)]
|
||||||
|
pub struct Keycloak {
|
||||||
|
pub realm_url: String,
|
||||||
|
pub client_id: String,
|
||||||
|
pub client_secret: String,
|
||||||
|
pub auth_url: String,
|
||||||
|
pub token_url: String,
|
||||||
|
pub redirect_url: String,
|
||||||
|
pub realm: String,
|
||||||
|
pub base_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn get_host_url(&self) -> String {
|
||||||
|
format!("{}:{}", self.host_ip, self.host_port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config_absolute_path() -> PathBuf {
|
||||||
|
PathBuf::from(CONFIG_FILE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config() -> Result<Config, Box<dyn std::error::Error>> {
|
||||||
|
if fs::exists(get_config_absolute_path())? {
|
||||||
|
Ok(toml::from_str(&fs::read_to_string(CONFIG_FILE)?)?)
|
||||||
|
} else {
|
||||||
|
let config = create_standard_config();
|
||||||
|
save_config(&config)?;
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_log_file_name(prefix: String) -> String {
|
||||||
|
format!("{}_{}.log", prefix, chrono::Local::now().format("%Y-%m-%dT%H-%M-%S%.6f%z"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_config(config: &Config) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
fs::write(get_config_absolute_path(), toml::to_string(config)?)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_standard_config() -> Config {
|
||||||
|
Config {
|
||||||
|
log_file_prefix: String::from("delivery_backend"),
|
||||||
|
host_ip: String::from("127.0.0.1"),
|
||||||
|
host_port: 3000,
|
||||||
|
redis_url: String::from("redis://127.0.0.1:6379"),
|
||||||
|
gsd_rest_url: String::from("http://127.0.0.1:8334"),
|
||||||
|
gsd_app_key: String::from("GSD-RestApi"),
|
||||||
|
frontend_url: String::from("http://127.0.0.1:3000"),
|
||||||
|
gsd_app_names: vec![String::from("GSD-RestApi")],
|
||||||
|
gsd_user: String::from("<GSD-USER>"),
|
||||||
|
gsd_password: String::from("<GSD-Password>"),
|
||||||
|
|
||||||
|
keycloak: Keycloak {
|
||||||
|
realm_url: String::from("http://127.0.0.1:8080/auth/realms/master"),
|
||||||
|
client_id: String::from("delivery-backend"),
|
||||||
|
client_secret: String::from(""),
|
||||||
|
realm: String::from("master"),
|
||||||
|
base_url: String::from("http://127.0.0.1:8080"),
|
||||||
|
auth_url: String::from(
|
||||||
|
"http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/auth",
|
||||||
|
),
|
||||||
|
token_url: String::from(
|
||||||
|
"http://127.0.0.1:8080/auth/realms/master/protocol/openid-connect/token",
|
||||||
|
),
|
||||||
|
redirect_url: String::from("http://127.0.0.1:3000/callback"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
331
src/dto.rs
Normal file
331
src/dto.rs
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct CarInfoDTO {
|
||||||
|
pub amount_deliveries: u32,
|
||||||
|
pub car: CarDTO,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct CarDTO {
|
||||||
|
pub id: u32,
|
||||||
|
pub car_name: String,
|
||||||
|
pub driver_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct GetCarInfosDTO {
|
||||||
|
pub deliveries: Vec<CarInfoDTO>,
|
||||||
|
pub date: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct ArticleDTO {
|
||||||
|
pub id: u64,
|
||||||
|
pub title: String,
|
||||||
|
pub quantity: u64,
|
||||||
|
pub price_per_quantity: f32,
|
||||||
|
pub deposit_price_per_quantity: f32,
|
||||||
|
pub quantity_delivered: u64,
|
||||||
|
pub quantity_returned: u64,
|
||||||
|
pub quantity_to_deposit: u64,
|
||||||
|
pub reference_to: Option<u64>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct AddressDTO {
|
||||||
|
pub street: String,
|
||||||
|
pub housing_number: String,
|
||||||
|
pub postal_code: String,
|
||||||
|
pub city: String,
|
||||||
|
pub country: Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct CustomerDTO {
|
||||||
|
pub name: String,
|
||||||
|
pub id: u64,
|
||||||
|
pub address: AddressDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct ReceiptDTO {
|
||||||
|
pub articles: Vec<ArticleDTO>,
|
||||||
|
pub customer: CustomerDTO,
|
||||||
|
|
||||||
|
pub total_gross_price: f32,
|
||||||
|
pub total_net_price: f32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct DeliveryDTO {
|
||||||
|
pub receipt: ReceiptDTO,
|
||||||
|
pub information_for_driver: String,
|
||||||
|
pub desired_delivery_time: DateTime<Utc>,
|
||||||
|
pub time_delivered: Option<DateTime<Utc>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
|
pub struct TourDTO {
|
||||||
|
pub car: CarDTO,
|
||||||
|
pub date: String,
|
||||||
|
pub deliveries: Vec<DeliveryDTO>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_example_deliveries() -> GetCarInfosDTO {
|
||||||
|
GetCarInfosDTO {
|
||||||
|
date: format!("{}", Utc::now().format("%d.%m.%Y")),
|
||||||
|
deliveries: vec![
|
||||||
|
CarInfoDTO {
|
||||||
|
car: CarDTO {
|
||||||
|
id: 1,
|
||||||
|
car_name: "OG DN 1998".to_string(),
|
||||||
|
driver_name: Some("Dennis Nemec".to_string()),
|
||||||
|
},
|
||||||
|
amount_deliveries: 12,
|
||||||
|
},
|
||||||
|
CarInfoDTO {
|
||||||
|
car: CarDTO {
|
||||||
|
id: 2,
|
||||||
|
car_name: "S SM 2547".to_string(),
|
||||||
|
driver_name: None // "Sarah Müller".to_string(),
|
||||||
|
},
|
||||||
|
amount_deliveries: 8,
|
||||||
|
},
|
||||||
|
CarInfoDTO {
|
||||||
|
car: CarDTO {
|
||||||
|
id: 3,
|
||||||
|
car_name: "M MS 3891".to_string(),
|
||||||
|
driver_name: Some("Michael Schmidt".to_string()),
|
||||||
|
},
|
||||||
|
amount_deliveries: 15,
|
||||||
|
},
|
||||||
|
CarInfoDTO {
|
||||||
|
car: CarDTO {
|
||||||
|
id: 4,
|
||||||
|
car_name: "KA AW 1024".to_string(),
|
||||||
|
driver_name: Some("Anna Weber".to_string()),
|
||||||
|
},
|
||||||
|
amount_deliveries: 6,
|
||||||
|
},
|
||||||
|
CarInfoDTO {
|
||||||
|
car: CarDTO {
|
||||||
|
id: 5,
|
||||||
|
car_name: "FR TB 7652".to_string(),
|
||||||
|
driver_name: None // "Thomas Becker".to_string(),
|
||||||
|
},
|
||||||
|
amount_deliveries: 11,
|
||||||
|
},
|
||||||
|
CarInfoDTO {
|
||||||
|
car: CarDTO {
|
||||||
|
id: 6,
|
||||||
|
car_name: "HD JH 4389".to_string(),
|
||||||
|
driver_name: Some("Julia Hoffmann".to_string()),
|
||||||
|
},
|
||||||
|
amount_deliveries: 9,
|
||||||
|
},
|
||||||
|
CarInfoDTO {
|
||||||
|
car: CarDTO {
|
||||||
|
id: 7,
|
||||||
|
car_name: "KN MF 5123".to_string(),
|
||||||
|
driver_name: Some("Markus Fischer".to_string()),
|
||||||
|
},
|
||||||
|
amount_deliveries: 13,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_test_tour(car_id: u64) -> TourDTO {
|
||||||
|
TourDTO {
|
||||||
|
car: CarDTO {
|
||||||
|
id: car_id as u32,
|
||||||
|
car_name: String::from("Mercedes Sprinter"),
|
||||||
|
driver_name: Some(String::from("Hans Müller")),
|
||||||
|
},
|
||||||
|
date: String::from("2026-02-05"),
|
||||||
|
deliveries: vec![
|
||||||
|
// Lieferung 1
|
||||||
|
DeliveryDTO {
|
||||||
|
receipt: ReceiptDTO {
|
||||||
|
articles: vec![
|
||||||
|
ArticleDTO {
|
||||||
|
id: 1001,
|
||||||
|
title: String::from("Propangas 5kg"),
|
||||||
|
quantity: 4,
|
||||||
|
price_per_quantity: 18.99,
|
||||||
|
deposit_price_per_quantity: 0.0,
|
||||||
|
quantity_delivered: 4,
|
||||||
|
quantity_returned: 0,
|
||||||
|
quantity_to_deposit: 0,
|
||||||
|
reference_to: None,
|
||||||
|
},
|
||||||
|
ArticleDTO {
|
||||||
|
id: 2001,
|
||||||
|
title: String::from("Pfandflasche 5kg"),
|
||||||
|
quantity: 4,
|
||||||
|
price_per_quantity: 0.0,
|
||||||
|
deposit_price_per_quantity: 35.00,
|
||||||
|
quantity_delivered: 4,
|
||||||
|
quantity_returned: 2,
|
||||||
|
quantity_to_deposit: 2,
|
||||||
|
reference_to: Some(1001),
|
||||||
|
},
|
||||||
|
ArticleDTO {
|
||||||
|
id: 1002,
|
||||||
|
title: String::from("Propangas 11kg"),
|
||||||
|
quantity: 2,
|
||||||
|
price_per_quantity: 32.99,
|
||||||
|
deposit_price_per_quantity: 0.0,
|
||||||
|
quantity_delivered: 2,
|
||||||
|
quantity_returned: 0,
|
||||||
|
quantity_to_deposit: 0,
|
||||||
|
reference_to: None,
|
||||||
|
},
|
||||||
|
ArticleDTO {
|
||||||
|
id: 2002,
|
||||||
|
title: String::from("Pfandflasche 11kg"),
|
||||||
|
quantity: 2,
|
||||||
|
price_per_quantity: 0.0,
|
||||||
|
deposit_price_per_quantity: 45.00,
|
||||||
|
quantity_delivered: 2,
|
||||||
|
quantity_returned: 1,
|
||||||
|
quantity_to_deposit: 1,
|
||||||
|
reference_to: Some(1002),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
customer: CustomerDTO {
|
||||||
|
name: String::from("Grillhütte Waldheim"),
|
||||||
|
id: 5001,
|
||||||
|
address: AddressDTO {
|
||||||
|
street: String::from("Waldstraße"),
|
||||||
|
housing_number: String::from("15"),
|
||||||
|
postal_code: String::from("70597"),
|
||||||
|
city: String::from("Stuttgart"),
|
||||||
|
country: Some(String::from("Deutschland")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
total_gross_price: 211.94,
|
||||||
|
total_net_price: 178.10,
|
||||||
|
},
|
||||||
|
information_for_driver: String::from("Flaschen beim Lagerraum hinter dem Gebäude abstellen. Alte Flaschen abholen."),
|
||||||
|
desired_delivery_time: Utc.with_ymd_and_hms(2026, 2, 5, 8, 0, 0).unwrap(),
|
||||||
|
time_delivered: None // Utc.with_ymd_and_hms(2026, 2, 5, 8, 15, 0).unwrap(),
|
||||||
|
},
|
||||||
|
|
||||||
|
// Lieferung 2
|
||||||
|
DeliveryDTO {
|
||||||
|
receipt: ReceiptDTO {
|
||||||
|
articles: vec![
|
||||||
|
ArticleDTO {
|
||||||
|
id: 1001,
|
||||||
|
title: String::from("Propangas 5kg"),
|
||||||
|
quantity: 8,
|
||||||
|
price_per_quantity: 18.99,
|
||||||
|
deposit_price_per_quantity: 0.0,
|
||||||
|
quantity_delivered: 8,
|
||||||
|
quantity_returned: 0,
|
||||||
|
quantity_to_deposit: 0,
|
||||||
|
reference_to: None,
|
||||||
|
},
|
||||||
|
ArticleDTO {
|
||||||
|
id: 2001,
|
||||||
|
title: String::from("Pfandflasche 5kg"),
|
||||||
|
quantity: 8,
|
||||||
|
price_per_quantity: 0.0,
|
||||||
|
deposit_price_per_quantity: 35.00,
|
||||||
|
quantity_delivered: 8,
|
||||||
|
quantity_returned: 7,
|
||||||
|
quantity_to_deposit: 1,
|
||||||
|
reference_to: Some(1001),
|
||||||
|
},
|
||||||
|
ArticleDTO {
|
||||||
|
id: 1003,
|
||||||
|
title: String::from("Propangas 33kg"),
|
||||||
|
quantity: 1,
|
||||||
|
price_per_quantity: 89.99,
|
||||||
|
deposit_price_per_quantity: 0.0,
|
||||||
|
quantity_delivered: 1,
|
||||||
|
quantity_returned: 0,
|
||||||
|
quantity_to_deposit: 0,
|
||||||
|
reference_to: None,
|
||||||
|
},
|
||||||
|
ArticleDTO {
|
||||||
|
id: 2003,
|
||||||
|
title: String::from("Pfandflasche 33kg"),
|
||||||
|
quantity: 1,
|
||||||
|
price_per_quantity: 0.0,
|
||||||
|
deposit_price_per_quantity: 75.00,
|
||||||
|
quantity_delivered: 1,
|
||||||
|
quantity_returned: 1,
|
||||||
|
quantity_to_deposit: 0,
|
||||||
|
reference_to: Some(1003),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
customer: CustomerDTO {
|
||||||
|
name: String::from("Campingplatz Sonnenhof"),
|
||||||
|
id: 5002,
|
||||||
|
address: AddressDTO {
|
||||||
|
street: String::from("Am See"),
|
||||||
|
housing_number: String::from("23"),
|
||||||
|
postal_code: String::from("70376"),
|
||||||
|
city: String::from("Stuttgart"),
|
||||||
|
country: Some(String::from("Deutschland")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
total_gross_price: 241.91,
|
||||||
|
total_net_price: 203.28,
|
||||||
|
},
|
||||||
|
information_for_driver: String::from("Rezeption informieren. Flaschen zur Gasflaschenhütte bei Stellplatz A12 bringen."),
|
||||||
|
desired_delivery_time: Utc.with_ymd_and_hms(2026, 2, 5, 10, 0, 0).unwrap(),
|
||||||
|
time_delivered: Some(Utc.with_ymd_and_hms(2026, 2, 5, 10, 20, 0).unwrap()),
|
||||||
|
},
|
||||||
|
|
||||||
|
// Lieferung 3
|
||||||
|
DeliveryDTO {
|
||||||
|
receipt: ReceiptDTO {
|
||||||
|
articles: vec![
|
||||||
|
ArticleDTO {
|
||||||
|
id: 1002,
|
||||||
|
title: String::from("Propangas 11kg"),
|
||||||
|
quantity: 6,
|
||||||
|
price_per_quantity: 32.99,
|
||||||
|
deposit_price_per_quantity: 0.0,
|
||||||
|
quantity_delivered: 6,
|
||||||
|
quantity_returned: 0,
|
||||||
|
quantity_to_deposit: 0,
|
||||||
|
reference_to: None,
|
||||||
|
},
|
||||||
|
ArticleDTO {
|
||||||
|
id: 2002,
|
||||||
|
title: String::from("Pfandflasche 11kg"),
|
||||||
|
quantity: 6,
|
||||||
|
price_per_quantity: 0.0,
|
||||||
|
deposit_price_per_quantity: 45.00,
|
||||||
|
quantity_delivered: 6,
|
||||||
|
quantity_returned: 5,
|
||||||
|
quantity_to_deposit: 1,
|
||||||
|
reference_to: Some(1002),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
customer: CustomerDTO {
|
||||||
|
name: String::from("Baumarkt Schmidt GmbH"),
|
||||||
|
id: 5003,
|
||||||
|
address: AddressDTO {
|
||||||
|
street: String::from("Industriestraße"),
|
||||||
|
housing_number: String::from("88"),
|
||||||
|
postal_code: String::from("70565"),
|
||||||
|
city: String::from("Stuttgart"),
|
||||||
|
country: Some(String::from("Deutschland")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
total_gross_price: 242.94,
|
||||||
|
total_net_price: 204.15,
|
||||||
|
},
|
||||||
|
information_for_driver: String::from("Wareneingang nutzen, Anlieferung nur bis 12 Uhr möglich."),
|
||||||
|
desired_delivery_time: Utc.with_ymd_and_hms(2026, 2, 5, 11, 30, 0).unwrap(),
|
||||||
|
time_delivered: Some(Utc.with_ymd_and_hms(2026, 2, 5, 11, 45, 0).unwrap()),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/gsd.rs
Normal file
2
src/gsd.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub(crate) mod dto;
|
||||||
|
pub(crate) mod service;
|
||||||
27
src/gsd/dto.rs
Normal file
27
src/gsd/dto.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct GSDLoginRequestDTO {
|
||||||
|
pub user: String,
|
||||||
|
pub pass: String,
|
||||||
|
pub app_names: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct GSDResponseDTO {
|
||||||
|
pub status: Option<GSDResponseStatusDTO>,
|
||||||
|
pub data: Option<GSDLoginResponseDataDTO>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct GSDLoginResponseDataDTO {
|
||||||
|
pub session_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, serde::Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct GSDResponseStatusDTO {
|
||||||
|
pub internal_status: String,
|
||||||
|
pub status_message: String,
|
||||||
|
}
|
||||||
134
src/gsd/service.rs
Normal file
134
src/gsd/service.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
use crate::config::Config;
|
||||||
|
use crate::gsd::dto::*;
|
||||||
|
use axum::body::Body;
|
||||||
|
use axum::extract::Request;
|
||||||
|
use log::{error, info};
|
||||||
|
use reqwest::Response;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GSDService {
|
||||||
|
host_url: String,
|
||||||
|
app_names: Vec<String>,
|
||||||
|
app_key: String,
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GSDServiceError {
|
||||||
|
LoginFailed,
|
||||||
|
LoginResponseParsingFailed,
|
||||||
|
RequestError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GSDService {
|
||||||
|
pub async fn get_session(&self) -> Result<String, GSDServiceError> {
|
||||||
|
info!(
|
||||||
|
"Session: No session found. Generate session from GSD server {}",
|
||||||
|
self.host_url
|
||||||
|
);
|
||||||
|
|
||||||
|
let dto = GSDLoginRequestDTO {
|
||||||
|
user: self.username.clone(),
|
||||||
|
pass: self.password.clone(),
|
||||||
|
app_names: self.app_names.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = reqwest::Client::new()
|
||||||
|
.post(format!("{}/v1/login", self.host_url.clone()))
|
||||||
|
.header("appKey", self.app_key.as_str())
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.json(&dto)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
error!("Session: error request to GSD: {}", e);
|
||||||
|
GSDServiceError::LoginFailed
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let response_dto: GSDResponseDTO = response.json().await.map_err(|e| {
|
||||||
|
error!("Session: error request to GSD: {}", e);
|
||||||
|
GSDServiceError::LoginResponseParsingFailed
|
||||||
|
})?;
|
||||||
|
let response_dto_unwrapped = response_dto.status.unwrap();
|
||||||
|
|
||||||
|
if response_dto_unwrapped.internal_status != "0" {
|
||||||
|
error!(
|
||||||
|
"Session: error message from GSD: {}",
|
||||||
|
response_dto_unwrapped.status_message
|
||||||
|
);
|
||||||
|
Err(GSDServiceError::LoginFailed)
|
||||||
|
} else {
|
||||||
|
match response_dto.data {
|
||||||
|
Some(data) => {
|
||||||
|
info!(
|
||||||
|
"Session: successfully obtained session with session id {:?}",
|
||||||
|
&data.session_id.as_ref()
|
||||||
|
);
|
||||||
|
Ok(data.session_id.unwrap())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
error!("Session: failed to obtain session id. No session id in request found.");
|
||||||
|
Err(GSDServiceError::LoginResponseParsingFailed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn forward_post_request(
|
||||||
|
&self,
|
||||||
|
request: Request<Body>,
|
||||||
|
) -> Result<Response, GSDServiceError> {
|
||||||
|
let (parts, body) = request.into_parts();
|
||||||
|
|
||||||
|
reqwest::Client::new()
|
||||||
|
.post(format!("{}{}", self.host_url.clone(), parts.uri))
|
||||||
|
.headers(parts.headers)
|
||||||
|
.body(axum::body::to_bytes(body, usize::MAX).await.unwrap())
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| GSDServiceError::RequestError(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn forward_patch_request(
|
||||||
|
&self,
|
||||||
|
request: Request<Body>,
|
||||||
|
) -> Result<Response, GSDServiceError> {
|
||||||
|
let (parts, body) = request.into_parts();
|
||||||
|
|
||||||
|
reqwest::Client::new()
|
||||||
|
.patch(format!("{}{}", self.host_url.clone(), parts.uri))
|
||||||
|
.headers(parts.headers)
|
||||||
|
.body(axum::body::to_bytes(body, usize::MAX).await.unwrap())
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| GSDServiceError::RequestError(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn forward_get_request(
|
||||||
|
&self,
|
||||||
|
request: Request<Body>,
|
||||||
|
) -> Result<Response, GSDServiceError> {
|
||||||
|
let (parts, body) = request.into_parts();
|
||||||
|
|
||||||
|
reqwest::Client::new()
|
||||||
|
.get(format!("{}{}", self.host_url.clone(), parts.uri))
|
||||||
|
.headers(parts.headers)
|
||||||
|
.body(axum::body::to_bytes(body, usize::MAX).await.unwrap())
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| GSDServiceError::RequestError(e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Config> for GSDService {
|
||||||
|
fn from(config: &Config) -> Self {
|
||||||
|
Self {
|
||||||
|
host_url: config.gsd_rest_url.clone(),
|
||||||
|
app_names: config.gsd_app_names.clone(),
|
||||||
|
app_key: config.gsd_app_key.clone(),
|
||||||
|
username: config.gsd_user.clone(),
|
||||||
|
password: config.gsd_password.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/main.rs
Normal file
84
src/main.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use crate::api::userinfo;
|
||||||
|
use crate::config::load_config;
|
||||||
|
use crate::middleware::AppState;
|
||||||
|
use crate::repository::RedisRepository;
|
||||||
|
use crate::util::initialize_logging;
|
||||||
|
use axum::routing::get;
|
||||||
|
use axum::{Extension, Router};
|
||||||
|
use axum_keycloak_auth::PassthroughMode;
|
||||||
|
use axum_keycloak_auth::instance::{KeycloakAuthInstance, KeycloakConfig};
|
||||||
|
use axum_keycloak_auth::layer::KeycloakAuthLayer;
|
||||||
|
use log::info;
|
||||||
|
use oauth2::url::Url;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
mod api;
|
||||||
|
mod auth;
|
||||||
|
mod config;
|
||||||
|
mod gsd;
|
||||||
|
mod middleware;
|
||||||
|
mod model;
|
||||||
|
mod repository;
|
||||||
|
mod util;
|
||||||
|
mod response;
|
||||||
|
mod dto;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let config = load_config()?;
|
||||||
|
initialize_logging(&config);
|
||||||
|
|
||||||
|
info!("Redirect URI: {}", config.keycloak.redirect_url);
|
||||||
|
info!("Logging initialized");
|
||||||
|
info!("Starting Gas Delivery Backend");
|
||||||
|
|
||||||
|
let redis_url = config.redis_url.clone();
|
||||||
|
let host_url = config.get_host_url().clone();
|
||||||
|
|
||||||
|
info!("Initializing redis server");
|
||||||
|
let state = Arc::new(AppState {
|
||||||
|
config: config.clone(),
|
||||||
|
repository: RedisRepository::try_new(redis_url).await?,
|
||||||
|
gsd_service: (&config).into(),
|
||||||
|
oauth_client: auth::create_oauth_client(&config),
|
||||||
|
frontend_url: config.frontend_url.clone(),
|
||||||
|
});
|
||||||
|
//
|
||||||
|
info!("Starting axum server");
|
||||||
|
|
||||||
|
let keycloak_instance: Arc<KeycloakAuthInstance> = Arc::new(KeycloakAuthInstance::new(
|
||||||
|
KeycloakConfig::builder()
|
||||||
|
.server(Url::parse(config.keycloak.base_url.as_str())?)
|
||||||
|
.realm(config.keycloak.realm)
|
||||||
|
.build(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let auth_router = auth::router(state.clone());
|
||||||
|
let api_router = Router::new()
|
||||||
|
.route("/cars", get(api::supplier::load_supplier_cars))
|
||||||
|
.route("/tour/{car_id}", get(api::tour::load_tour))
|
||||||
|
.route("/userinfo", get(userinfo))
|
||||||
|
.route_layer(Extension(state.clone()))
|
||||||
|
.route_layer(
|
||||||
|
KeycloakAuthLayer::<String>::builder()
|
||||||
|
.instance(keycloak_instance.clone())
|
||||||
|
.passthrough_mode(PassthroughMode::Block)
|
||||||
|
.persist_raw_claims(false)
|
||||||
|
.expected_audiences(vec![String::from("account")])
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.route_layer(axum::middleware::from_fn_with_state(
|
||||||
|
state.clone(),
|
||||||
|
middleware::session_auth_middleware,
|
||||||
|
))
|
||||||
|
.with_state(state);
|
||||||
|
|
||||||
|
let app = Router::new().merge(api_router).merge(auth_router);
|
||||||
|
|
||||||
|
info!("Listening on {}", host_url);
|
||||||
|
let listener = tokio::net::TcpListener::bind(host_url.clone()).await?;
|
||||||
|
|
||||||
|
axum::serve(listener, app).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
168
src/middleware.rs
Normal file
168
src/middleware.rs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
use crate::auth::{OAuthClient, UserSession, refresh_access_token_internal};
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::gsd::service::GSDService;
|
||||||
|
use crate::repository::RedisRepository;
|
||||||
|
use crate::util::set_and_log_session;
|
||||||
|
use axum::extract::{Request, State};
|
||||||
|
use axum::http::{HeaderValue, StatusCode};
|
||||||
|
use axum::middleware::Next;
|
||||||
|
use axum::response::{IntoResponse, Response};
|
||||||
|
use axum_extra::extract::CookieJar;
|
||||||
|
use log::{error, info, warn};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AppState {
|
||||||
|
pub config: Config,
|
||||||
|
pub repository: RedisRepository,
|
||||||
|
pub gsd_service: GSDService,
|
||||||
|
pub oauth_client: OAuthClient,
|
||||||
|
pub frontend_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Middleware to validate session and refresh tokens if needed
|
||||||
|
pub async fn session_auth_middleware(
|
||||||
|
jar: CookieJar,
|
||||||
|
State(state): State<Arc<AppState>>,
|
||||||
|
mut request: Request,
|
||||||
|
next: Next,
|
||||||
|
) -> Response {
|
||||||
|
// 1. Extract session ID from cookie
|
||||||
|
let session_id = match jar.get("session_id") {
|
||||||
|
Some(cookie) => cookie.value().to_string(),
|
||||||
|
None => {
|
||||||
|
warn!("No session cookie found");
|
||||||
|
return (StatusCode::UNAUTHORIZED, "No session cookie").into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Find session in Redis
|
||||||
|
let session_key = format!("user_session:{}", session_id);
|
||||||
|
let session_json = match state.repository.get(&session_key).await {
|
||||||
|
Ok(Some(json)) => json,
|
||||||
|
Ok(None) => {
|
||||||
|
warn!("Session not found in Redis: {}", session_id);
|
||||||
|
return (StatusCode::UNAUTHORIZED, "Session expired or invalid").into_response();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Redis error while fetching session: {:?}", e);
|
||||||
|
return (StatusCode::INTERNAL_SERVER_ERROR, "Internal error").into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 3. Parse session data
|
||||||
|
let mut user_session: UserSession = match serde_json::from_str(&session_json) {
|
||||||
|
Ok(session) => session,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to parse session JSON: {:?}", e);
|
||||||
|
return (StatusCode::INTERNAL_SERVER_ERROR, "Invalid session data").into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 4. Check if access token is expired
|
||||||
|
let now = chrono::Utc::now().timestamp();
|
||||||
|
if user_session.expires_at <= now {
|
||||||
|
info!(
|
||||||
|
"Access token expired for session {}, attempting refresh",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
// 5. Refresh the access token using refresh token
|
||||||
|
match refresh_access_token_internal(
|
||||||
|
&state.oauth_client,
|
||||||
|
&state.repository,
|
||||||
|
&session_id,
|
||||||
|
&mut user_session,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(new_access_token) => {
|
||||||
|
info!(
|
||||||
|
"Successfully refreshed access token for session {}",
|
||||||
|
session_id
|
||||||
|
);
|
||||||
|
user_session.access_token = new_access_token;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to refresh access token: {}", e);
|
||||||
|
// Clean up invalid session
|
||||||
|
let _ = state.repository.delete(&session_key).await;
|
||||||
|
return (
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
"Session expired, please login again",
|
||||||
|
)
|
||||||
|
.into_response();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
"Access token still valid for session {} (expires in {} seconds)",
|
||||||
|
session_id,
|
||||||
|
user_session.expires_at - now
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Attach validated access token to request for downstream handlers
|
||||||
|
match HeaderValue::from_str(format!("Bearer {}", &user_session.access_token).as_str()) {
|
||||||
|
Ok(header_value) => {
|
||||||
|
request.headers_mut().insert("authorization", header_value);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to create authorization header: {:?}", e);
|
||||||
|
return (StatusCode::INTERNAL_SERVER_ERROR, "Internal error").into_response();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Pass the request to the next handler
|
||||||
|
next.run(request).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn gsd_decorate_header(
|
||||||
|
State(state): State<Arc<AppState>>,
|
||||||
|
mut request: Request,
|
||||||
|
next: Next,
|
||||||
|
) -> Response {
|
||||||
|
let state_cloned = state.clone();
|
||||||
|
|
||||||
|
let session = state_cloned.repository.get_session().await;
|
||||||
|
match session {
|
||||||
|
Ok(session) => {
|
||||||
|
let session_value;
|
||||||
|
|
||||||
|
if session.is_none() {
|
||||||
|
match state_cloned.gsd_service.get_session().await {
|
||||||
|
Ok(session) => {
|
||||||
|
session_value = session.clone();
|
||||||
|
set_and_log_session(&state_cloned, session.clone()).await;
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
error!("Error getting session: {:?}", error);
|
||||||
|
return StatusCode::UNAUTHORIZED.into_response();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
session_value = session.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
request.headers_mut().insert(
|
||||||
|
"sessionId",
|
||||||
|
HeaderValue::from_str(session_value.as_str()).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
error!(
|
||||||
|
"Redis error occured during fetching current session id. Error: {}",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request.headers_mut().insert(
|
||||||
|
"appkey",
|
||||||
|
HeaderValue::from_str(state_cloned.config.gsd_app_key.as_str()).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
next.run(request).await
|
||||||
|
|
||||||
|
}
|
||||||
13
src/model.rs
Normal file
13
src/model.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
|
pub struct User {
|
||||||
|
pub employee: Employee,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Employee {
|
||||||
|
pub last_name: String,
|
||||||
|
pub first_name: String,
|
||||||
|
pub mail: String,
|
||||||
|
pub supplier_id: u64
|
||||||
|
}
|
||||||
51
src/repository.rs
Normal file
51
src/repository.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
use redis::aio::ConnectionManager;
|
||||||
|
use redis::{AsyncTypedCommands, Connection, RedisError, RedisResult};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RedisRepository {
|
||||||
|
connection_manager: ConnectionManager,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RedisRepository {
|
||||||
|
pub async fn try_new(redis_url: String) -> Result<RedisRepository, RedisError> {
|
||||||
|
Ok(RedisRepository {
|
||||||
|
connection_manager: redis::Client::open(redis_url)?
|
||||||
|
.get_connection_manager()
|
||||||
|
.await?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_session(&self) -> RedisResult<Option<String>> {
|
||||||
|
self.connection_manager
|
||||||
|
.clone()
|
||||||
|
.get::<String>("current_session".to_string())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_session(&self, session: String) -> RedisResult<()> {
|
||||||
|
self.connection_manager
|
||||||
|
.clone()
|
||||||
|
.set("current_session", session)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_with_expiry(&self, key: &str, value: &str, expiry: u64) -> RedisResult<()> {
|
||||||
|
self.connection_manager
|
||||||
|
.clone()
|
||||||
|
.set_ex(key, value, expiry)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get(&self, key: &str) -> RedisResult<Option<String>> {
|
||||||
|
self.connection_manager
|
||||||
|
.clone()
|
||||||
|
.get::<String>(key.to_string())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete(&self, key: &str) -> RedisResult<usize> {
|
||||||
|
self.connection_manager.clone().del(key.to_string()).await
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/response.rs
Normal file
20
src/response.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use axum::Json;
|
||||||
|
use axum::response::{IntoResponse, Response};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
pub struct ResponseFactory {}
|
||||||
|
impl ResponseFactory {
|
||||||
|
pub fn error(message: String, code: Option<u32>) -> FailResponse {
|
||||||
|
FailResponse {
|
||||||
|
code,
|
||||||
|
message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct FailResponse {
|
||||||
|
pub code: Option<u32>,
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
47
src/util.rs
Normal file
47
src/util.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use crate::config::{Config, generate_log_file_name};
|
||||||
|
use crate::middleware::AppState;
|
||||||
|
use log::{LevelFilter, error, info};
|
||||||
|
use simplelog::{ColorChoice, CombinedLogger, TermLogger, TerminalMode, WriteLogger};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
|
||||||
|
|
||||||
|
pub fn decode_payload_unchecked<T: DeserializeOwned>(token: &str) -> Result<T, Box<dyn std::error::Error>> {
|
||||||
|
let mut parts = token.split('.');
|
||||||
|
let _header = parts.next().ok_or("missing header")?;
|
||||||
|
let payload_b64 = parts.next().ok_or("missing payload")?;
|
||||||
|
// signature is parts.next() but we ignore it here
|
||||||
|
let payload = URL_SAFE_NO_PAD.decode(payload_b64.as_bytes())?;
|
||||||
|
let claims = serde_json::from_slice::<T>(&payload)?;
|
||||||
|
Ok(claims)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialize_logging(config: &Config) {
|
||||||
|
CombinedLogger::init(vec![
|
||||||
|
TermLogger::new(
|
||||||
|
LevelFilter::Info,
|
||||||
|
simplelog::Config::default(),
|
||||||
|
TerminalMode::Mixed,
|
||||||
|
ColorChoice::Auto,
|
||||||
|
),
|
||||||
|
WriteLogger::new(
|
||||||
|
LevelFilter::Info,
|
||||||
|
simplelog::Config::default(),
|
||||||
|
File::create(generate_log_file_name(config.log_file_prefix.clone())).unwrap(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_and_log_session(state: &Arc<AppState>, session: String) {
|
||||||
|
match state.repository.set_session(session.clone()).await {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Redis: saved session {}", &session);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(err) => {
|
||||||
|
error!("Redis: failed to save session: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user