diff --git a/bin/build-errors.log b/bin/build-errors.log index 5b7d352..34840bf 100644 --- a/bin/build-errors.log +++ b/bin/build-errors.log @@ -1 +1 @@ -exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file diff --git a/bin/main b/bin/main index cc42830..b565b0b 100755 Binary files a/bin/main and b/bin/main differ diff --git a/cmd/api/api.go b/cmd/api/api.go index 5019184..247fa1c 100644 --- a/cmd/api/api.go +++ b/cmd/api/api.go @@ -139,7 +139,7 @@ func (api *api) mount() http.Handler { r.Route("/users", func(r chi.Router) { r.Put("/activate/{token}", api.activateUserHandler) - //r.Put("/reset-password/{token}", api.resetPasswordHandler) + r.Put("/reset-password/{token}", api.resetPasswordHandler) r.Route("/me", func(r chi.Router) { r.Use(api.AuthTokenMiddleware) @@ -155,19 +155,17 @@ func (api *api) mount() http.Handler { r.Post("/forgot-password", api.forgotPasswordHandler) r.Post("/refresh", api.refreshTokenHandler) }) - }) - r.Route("/admin", func(r chi.Router) { - r.Use(api.AuthTokenMiddleware) + r.Route("/admin", func(r chi.Router) { + r.Use(api.AuthTokenMiddleware) - r.Route("/users", func(r chi.Router) { - r.Get("/", api.protectAdminRoutes("moderator", api.getUsersHandler)) - - r.Route("/{id}", func(r chi.Router) { - r.Get("/", api.protectAdminRoutes("moderator", api.getUserByIdHandler)) + r.Route("/users", func(r chi.Router) { + r.Get("/", api.protectAdminRoutes("moderator", api.getUsersHandler)) + r.Route("/{id}", func(r chi.Router) { + //r.Get("/", api.protectAdminRoutes("moderator", api.getUserByIdHandler)) + }) }) }) - }) return r diff --git a/cmd/api/api_test.go b/cmd/api/api_test.go index 3b7ff24..439f06d 100644 --- a/cmd/api/api_test.go +++ b/cmd/api/api_test.go @@ -28,7 +28,7 @@ func TestRateLimiterMiddleware(t *testing.T) { mockIP := "192.168.1.1" marginOfError := 2 - for i := 0; i < cfg.rateLimiter.RequestsPerTimeFrame+marginOfError; i++ { + for i := range cfg.rateLimiter.RequestsPerTimeFrame + marginOfError { req, err := http.NewRequest("GET", ts.URL+"/v1/health", nil) if err != nil { t.Fatalf("failed to create request: %v", err) diff --git a/cmd/api/auth.go b/cmd/api/auth.go index aefa8bf..6838ab9 100644 --- a/cmd/api/auth.go +++ b/cmd/api/auth.go @@ -5,7 +5,10 @@ import ( "encoding/hex" "errors" "fmt" + "log" "net/http" + "strconv" + "strings" "time" "github.com/FernandoVideira/LK_API_Temp/internal/mailer" @@ -47,7 +50,7 @@ type AuthResponse struct { // @Success 201 {object} UserWithToken "User Registered" // @Failure 400 {object} error "User payload error" // @Failure 500 {object} error "Internal Server Error" -// @Router /authentication/user [post] +// @Router /authentication/register [post] func (api *api) registerUserHandler(w http.ResponseWriter, r *http.Request) { var payload RegisterUserPayload if err := readJSON(w, r, &payload); err != nil { @@ -187,25 +190,76 @@ func (api *api) createTokenHandler(w http.ResponseWriter, r *http.Request) { return } - claims := &jwt.MapClaims{ - "sub": user.ID, - "exp": time.Now().Add(api.config.auth.token.exp).Unix(), - "iat": time.Now().Unix(), - "nbf": time.Now().Unix(), - "iss": api.config.auth.token.iss, - "aud": api.config.auth.token.aud, - } - - //* generate a new token -> add the claims - token, err := api.authenticator.GenerateToken(claims) + //* send the token back to the user + authResponse, err := api.createTokens(user) if err != nil { api.internalServerError(w, r, err) return } - //* send the token back to the user + if err := api.jsonResponse(w, http.StatusCreated, authResponse); err != nil { + api.internalServerError(w, r, err) + return + } +} - if err := api.jsonResponse(w, http.StatusCreated, token); err != nil { +// RefreshTokenHandler godoc +// +// @Summary Refresh a token +// @Description Refresh a token for the user +// @Tags authentication +// @Accept json +// @Produce json +// @Param Authorization header string true "Refresh Token" +// @Success 201 {string} string "Token Created" +// @Failure 400 {object} error +// @Failure 401 {object} error +// @Failure 500 {object} error +// @Router /authentication/refresh [post] +func (api *api) refreshTokenHandler(w http.ResponseWriter, r *http.Request) { + //* parse the refresh token from the request + refreshHeader := r.Header.Get("Authorization") + if refreshHeader == "" { + api.unauthorizedError(w, r, errors.New("refresh token is required")) + return + } + parts := strings.Split(refreshHeader, " ") + if len(parts) != 2 || parts[0] != "Bearer" { + api.unauthorizedError(w, r, fmt.Errorf("invalid Authorization header")) + return + } + + refreshToken := parts[1] + + token, err := api.authenticator.ValidateRefreshToken(refreshToken) + if err != nil { + api.unauthorizedError(w, r, err) + return + } + + claims := token.Claims.(jwt.MapClaims) + + //* get the user id from the token + userID, err := strconv.ParseInt(fmt.Sprintf("%.f", claims["sub"]), 10, 64) + if err != nil { + api.unauthorizedError(w, r, fmt.Errorf("invalid token")) + return + } + + //* get the user from the database + user, err := api.store.Users.GetByID(r.Context(), userID) + if err != nil { + api.unauthorizedError(w, r, err) + return + } + + authResponse, err := api.createTokens(user) + if err != nil { + api.unauthorizedError(w, r, err) + return + } + + if err := api.jsonResponse(w, http.StatusCreated, authResponse); err != nil { api.internalServerError(w, r, err) return } @@ -288,3 +342,37 @@ func (api *api) forgotPasswordHandler(w http.ResponseWriter, r *http.Request) { return } } + +func (api *api) createTokens(user *store.User) (AuthResponse, error) { + claims := &jwt.MapClaims{ + "sub": user.ID, + "exp": time.Now().Add(api.config.auth.token.exp).Unix(), + "iat": time.Now().Unix(), + "nbf": time.Now().Unix(), + "iss": api.config.auth.token.iss, + "aud": api.config.auth.token.aud, + } + + //* generate a new token -> add the claims + token, err := api.authenticator.GenerateToken(claims) + if err != nil { + return AuthResponse{}, err + } + + refreshClaims := &jwt.MapClaims{ + "sub": user.ID, + "exp": time.Now().Add(api.config.auth.token.refreshExp).Unix(), + } + + log.Println(time.Now().Add(api.config.auth.token.refreshExp).Unix()) + + refreshToken, err := api.authenticator.GenerateRefreshToken(refreshClaims) + if err != nil { + return AuthResponse{}, err + } + + return AuthResponse{ + Token: token, + RefreshToken: refreshToken, + }, nil +} diff --git a/cmd/api/main.go b/cmd/api/main.go index a63e1a8..697c541 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -69,10 +69,11 @@ func main() { password: env.GetString("BASIC_AUTH_PASSWORD", "admin"), }, token: tokenConfig{ - secret: env.GetString("AUTH_TOKEN_SECRET", "secret"), - exp: env.GetDuration("AUTH_TOKEN_EXP", "24h"), - iss: env.GetString("AUTH_TOKEN_ISS", "lkapi"), - aud: env.GetString("AUTH_TOKEN_AUD", "lkapi"), + secret: env.GetString("AUTH_TOKEN_SECRET", "secret"), + exp: env.GetDuration("AUTH_TOKEN_EXP", "24h"), + refreshExp: time.Hour * 24 * 7, + iss: env.GetString("AUTH_TOKEN_ISS", "lkapi"), + aud: env.GetString("AUTH_TOKEN_AUD", "lkapi"), }, }, rateLimiter: ratelimiter.Config{ diff --git a/cmd/api/middleware.go b/cmd/api/middleware.go index 24a7eae..a2d1c9e 100644 --- a/cmd/api/middleware.go +++ b/cmd/api/middleware.go @@ -5,7 +5,6 @@ import ( "encoding/base64" "errors" "fmt" - "log" "net/http" "strconv" "strings" @@ -109,7 +108,6 @@ func (api *api) postsContextMiddleware(next http.Handler) http.Handler { ctx := r.Context() post, err := api.store.Posts.GetByID(ctx, id) - log.Println("post", post) if err != nil { switch { case errors.Is(err, store.ErrNotFound): @@ -126,6 +124,19 @@ func (api *api) postsContextMiddleware(next http.Handler) http.Handler { }) } +func (api *api) rateLimiterMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if api.config.rateLimiter.Enabled { + if allow, retryAfter := api.rateLimiter.Allow(r.RemoteAddr); !allow { + api.rateLimitExceededError(w, r, retryAfter.String()) + return + } + } + + next.ServeHTTP(w, r) + }) +} + func (api *api) checkPostOwnership(requiredRole string, next http.HandlerFunc) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user := getUserFromContext(r) @@ -179,10 +190,7 @@ func (api *api) protectAdminRoutes(requiredRole string, next http.HandlerFunc) h return } - ctx := r.Context() - - ctx = context.WithValue(ctx, roleContextKey, user.Role) - next.ServeHTTP(w, r.WithContext(ctx)) + next.ServeHTTP(w, r) }) } @@ -218,16 +226,3 @@ func (api *api) getUser(ctx context.Context, id int64) (*store.User, error) { return user, nil } - -func (api *api) RateLimiterMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if api.config.rateLimiter.Enabled { - if allow, retryAfter := api.rateLimiter.Allow(r.RemoteAddr); !allow { - api.rateLimitExceededError(w, r, retryAfter.String()) - return - } - } - - next.ServeHTTP(w, r) - }) -} diff --git a/cmd/api/users.go b/cmd/api/users.go index a2cfea3..b619689 100644 --- a/cmd/api/users.go +++ b/cmd/api/users.go @@ -30,13 +30,13 @@ const roleContextKey roleKey = "role" // @Security ApiKeyAuth // @Router /admin/users [get] func (api *api) getUsersHandler(w http.ResponseWriter, r *http.Request) { - role := getRoleFromContext(r) - isAdmin := false - if role.Level == 3 { - isAdmin = true + user := getUserFromContext(r) + if user == nil { + api.unauthorizedError(w, r, errors.New("user not found")) + return } - users, err := api.store.Users.GetAll(r.Context(), isAdmin) + users, err := api.store.Users.GetAll(r.Context(), user.ID, user.Role.Level) if err != nil { api.internalServerError(w, r, err) return @@ -84,6 +84,57 @@ func (api *api) getUserHandler(w http.ResponseWriter, r *http.Request) { } } +type resetPasswordPayload struct { + NewPassword string `json:"new_password" validate:"required,password"` + NewPasswordConfirmation string `json:"new_password_confirmation" validate:"required,eqfield=NewPassword"` +} + +// ResetPassword godoc +// +// @Summary Reset user password +// @Description Reset user password with verification +// @Tags users +// @Accept json +// @Param payload body resetPasswordPayload true "Reset Password" +// @Param token path string true "Reset Password Token" +// @Success 204 {string} string "Password reset successfully" +// @Failure 400 {object} error "Invalid request" +// @Failure 401 {object} error "Unauthorized" +// @Failure 500 {object} error "Internal server error" +// @Security ApiKeyAuth +// @Router /users/reset-password/{token} [put] +func (api *api) resetPasswordHandler(w http.ResponseWriter, r *http.Request) { + token := chi.URLParam(r, "token") + + var payload resetPasswordPayload + if err := readJSON(w, r, &payload); err != nil { + api.badRequestError(w, r, err) + return + } + + if err := Validate.Struct(payload); err != nil { + api.badRequestError(w, r, err) + return + } + + err := api.store.Users.ResetPassword(r.Context(), token, payload.NewPassword) + if err != nil { + switch err { + case store.ErrNotFound: + api.notFoundError(w, r, err) + return + default: + api.internalServerError(w, r, err) + return + } + } + + w.WriteHeader(http.StatusNoContent) + if err := api.jsonResponse(w, http.StatusNoContent, ""); err != nil { + api.internalServerError(w, r, err) + } +} + type updateUserPayload struct { FirstName *string `json:"first_name" validate:"omitempty,max=100"` LastName *string `json:"last_name" validate:"omitempty,max=100"` @@ -331,8 +382,3 @@ func getUserFromContext(r *http.Request) *store.User { user, _ := r.Context().Value(userContextKey).(*store.User) return user } - -func getRoleFromContext(r *http.Request) *store.Role { - role, _ := r.Context().Value(roleContextKey).(*store.Role) - return role -} diff --git a/docs/docs.go b/docs/docs.go index 6f36702..5349e83 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -24,6 +24,46 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/admin/users": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches all users", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "Fetches all users", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.User" + } + }, + "400": { + "description": "Bad Request", + "schema": {} + }, + "404": { + "description": "Not Found", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, "/authentication/forgot-password": { "post": { "description": "Forgot Password", @@ -70,6 +110,92 @@ const docTemplate = `{ } } }, + "/authentication/refresh": { + "post": { + "description": "Refresh a token for the user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "authentication" + ], + "summary": "Refresh a token", + "parameters": [ + { + "type": "string", + "description": "Refresh Token", + "name": "Authorization", + "in": "header", + "required": true + } + ], + "responses": { + "201": { + "description": "Token Created", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": {} + }, + "401": { + "description": "Unauthorized", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, + "/authentication/register": { + "post": { + "description": "Register a new User", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "authentication" + ], + "summary": "Register a new User", + "parameters": [ + { + "description": "User Credentials", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/main.RegisterUserPayload" + } + } + ], + "responses": { + "201": { + "description": "User Registered", + "schema": { + "$ref": "#/definitions/main.UserWithToken" + } + }, + "400": { + "description": "User payload error", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, "/authentication/token": { "post": { "description": "Create a new token for the user", @@ -116,48 +242,6 @@ const docTemplate = `{ } } }, - "/authentication/user": { - "post": { - "description": "Register a new User", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "authentication" - ], - "summary": "Register a new User", - "parameters": [ - { - "description": "User Credentials", - "name": "payload", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/main.RegisterUserPayload" - } - } - ], - "responses": { - "201": { - "description": "User Registered", - "schema": { - "$ref": "#/definitions/main.UserWithToken" - } - }, - "400": { - "description": "User payload error", - "schema": {} - }, - "500": { - "description": "Internal Server Error", - "schema": {} - } - } - } - }, "/health": { "get": { "description": "Health Check", @@ -555,6 +639,61 @@ const docTemplate = `{ } } }, + "/users/reset-password/{token}": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Reset user password with verification", + "consumes": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Reset user password", + "parameters": [ + { + "description": "Reset Password", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/main.resetPasswordPayload" + } + }, + { + "type": "string", + "description": "Reset Password Token", + "name": "token", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Password reset successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid request", + "schema": {} + }, + "401": { + "description": "Unauthorized", + "schema": {} + }, + "500": { + "description": "Internal server error", + "schema": {} + } + } + } + }, "/users/{id}": { "get": { "security": [ @@ -935,6 +1074,21 @@ const docTemplate = `{ } } }, + "main.resetPasswordPayload": { + "type": "object", + "required": [ + "new_password", + "new_password_confirmation" + ], + "properties": { + "new_password": { + "type": "string" + }, + "new_password_confirmation": { + "type": "string" + } + } + }, "main.updateUserPasswordPayload": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 32710f4..fd61cec 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -16,6 +16,46 @@ }, "basePath": "/v1", "paths": { + "/admin/users": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches all users", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "Fetches all users", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/store.User" + } + }, + "400": { + "description": "Bad Request", + "schema": {} + }, + "404": { + "description": "Not Found", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, "/authentication/forgot-password": { "post": { "description": "Forgot Password", @@ -62,6 +102,92 @@ } } }, + "/authentication/refresh": { + "post": { + "description": "Refresh a token for the user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "authentication" + ], + "summary": "Refresh a token", + "parameters": [ + { + "type": "string", + "description": "Refresh Token", + "name": "Authorization", + "in": "header", + "required": true + } + ], + "responses": { + "201": { + "description": "Token Created", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": {} + }, + "401": { + "description": "Unauthorized", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, + "/authentication/register": { + "post": { + "description": "Register a new User", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "authentication" + ], + "summary": "Register a new User", + "parameters": [ + { + "description": "User Credentials", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/main.RegisterUserPayload" + } + } + ], + "responses": { + "201": { + "description": "User Registered", + "schema": { + "$ref": "#/definitions/main.UserWithToken" + } + }, + "400": { + "description": "User payload error", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, "/authentication/token": { "post": { "description": "Create a new token for the user", @@ -108,48 +234,6 @@ } } }, - "/authentication/user": { - "post": { - "description": "Register a new User", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "authentication" - ], - "summary": "Register a new User", - "parameters": [ - { - "description": "User Credentials", - "name": "payload", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/main.RegisterUserPayload" - } - } - ], - "responses": { - "201": { - "description": "User Registered", - "schema": { - "$ref": "#/definitions/main.UserWithToken" - } - }, - "400": { - "description": "User payload error", - "schema": {} - }, - "500": { - "description": "Internal Server Error", - "schema": {} - } - } - } - }, "/health": { "get": { "description": "Health Check", @@ -547,6 +631,61 @@ } } }, + "/users/reset-password/{token}": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Reset user password with verification", + "consumes": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Reset user password", + "parameters": [ + { + "description": "Reset Password", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/main.resetPasswordPayload" + } + }, + { + "type": "string", + "description": "Reset Password Token", + "name": "token", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Password reset successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid request", + "schema": {} + }, + "401": { + "description": "Unauthorized", + "schema": {} + }, + "500": { + "description": "Internal server error", + "schema": {} + } + } + } + }, "/users/{id}": { "get": { "security": [ @@ -927,6 +1066,21 @@ } } }, + "main.resetPasswordPayload": { + "type": "object", + "required": [ + "new_password", + "new_password_confirmation" + ], + "properties": { + "new_password": { + "type": "string" + }, + "new_password_confirmation": { + "type": "string" + } + } + }, "main.updateUserPasswordPayload": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e898de6..cc512b7 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -94,6 +94,16 @@ definitions: username: type: string type: object + main.resetPasswordPayload: + properties: + new_password: + type: string + new_password_confirmation: + type: string + required: + - new_password + - new_password_confirmation + type: object main.updateUserPasswordPayload: properties: current_password: @@ -238,6 +248,32 @@ info: termsOfService: http://swagger.io/terms/ title: LK API Template paths: + /admin/users: + get: + consumes: + - application/json + description: Fetches all users + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/store.User' + "400": + description: Bad Request + schema: {} + "404": + description: Not Found + schema: {} + "500": + description: Internal Server Error + schema: {} + security: + - ApiKeyAuth: [] + summary: Fetches all users + tags: + - admin /authentication/forgot-password: post: consumes: @@ -269,6 +305,64 @@ paths: summary: Forgot Password tags: - authentication + /authentication/refresh: + post: + consumes: + - application/json + description: Refresh a token for the user + parameters: + - description: Refresh Token + in: header + name: Authorization + required: true + type: string + produces: + - application/json + responses: + "201": + description: Token Created + schema: + type: string + "400": + description: Bad Request + schema: {} + "401": + description: Unauthorized + schema: {} + "500": + description: Internal Server Error + schema: {} + summary: Refresh a token + tags: + - authentication + /authentication/register: + post: + consumes: + - application/json + description: Register a new User + parameters: + - description: User Credentials + in: body + name: payload + required: true + schema: + $ref: '#/definitions/main.RegisterUserPayload' + produces: + - application/json + responses: + "201": + description: User Registered + schema: + $ref: '#/definitions/main.UserWithToken' + "400": + description: User payload error + schema: {} + "500": + description: Internal Server Error + schema: {} + summary: Register a new User + tags: + - authentication /authentication/token: post: consumes: @@ -300,34 +394,6 @@ paths: summary: Create a new token tags: - authentication - /authentication/user: - post: - consumes: - - application/json - description: Register a new User - parameters: - - description: User Credentials - in: body - name: payload - required: true - schema: - $ref: '#/definitions/main.RegisterUserPayload' - produces: - - application/json - responses: - "201": - description: User Registered - schema: - $ref: '#/definitions/main.UserWithToken' - "400": - description: User payload error - schema: {} - "500": - description: Internal Server Error - schema: {} - summary: Register a new User - tags: - - authentication /health: get: description: Health Check @@ -756,6 +822,42 @@ paths: summary: Fetches the user feed tags: - feed + /users/reset-password/{token}: + put: + consumes: + - application/json + description: Reset user password with verification + parameters: + - description: Reset Password + in: body + name: payload + required: true + schema: + $ref: '#/definitions/main.resetPasswordPayload' + - description: Reset Password Token + in: path + name: token + required: true + type: string + responses: + "204": + description: Password reset successfully + schema: + type: string + "400": + description: Invalid request + schema: {} + "401": + description: Unauthorized + schema: {} + "500": + description: Internal server error + schema: {} + security: + - ApiKeyAuth: [] + summary: Reset user password + tags: + - users securityDefinitions: ApiKeyAuth: in: header diff --git a/go.mod b/go.mod index 7d970af..b993317 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/FernandoVideira/LK_API_Temp go 1.23.4 require ( + github.com/Masterminds/squirrel v1.5.4 github.com/go-chi/chi/v5 v5.2.0 github.com/go-chi/cors v1.2.1 github.com/go-playground/validator/v10 v10.24.0 @@ -20,7 +21,6 @@ require ( require ( github.com/KyleBanks/depth v1.2.1 // indirect - github.com/Masterminds/squirrel v1.5.4 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 1cc8098..d05b4c8 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -4,5 +4,7 @@ import "github.com/golang-jwt/jwt/v5" type Authenticator interface { GenerateToken(jwt.Claims) (string, error) + GenerateRefreshToken(jwt.Claims) (string, error) ValidateToken(string) (*jwt.Token, error) + ValidateRefreshToken(string) (*jwt.Token, error) } diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go index 5734375..4775ab1 100644 --- a/internal/auth/jwt.go +++ b/internal/auth/jwt.go @@ -31,6 +31,17 @@ func (j *JWTAuthenticator) GenerateToken(claims jwt.Claims) (string, error) { return tokenString, nil } +func (j *JWTAuthenticator) GenerateRefreshToken(claims jwt.Claims) (string, error) { + refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + refreshTokenString, err := refreshToken.SignedString([]byte(j.secret)) + if err != nil { + return "", err + } + + return refreshTokenString, nil +} + func (j *JWTAuthenticator) ValidateToken(tokenString string) (*jwt.Token, error) { return jwt.Parse(tokenString, func(t *jwt.Token) (any, error) { if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { @@ -45,3 +56,16 @@ func (j *JWTAuthenticator) ValidateToken(tokenString string) (*jwt.Token, error) jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Name}), ) } + +func (j *JWTAuthenticator) ValidateRefreshToken(tokenString string) (*jwt.Token, error) { + return jwt.Parse(tokenString, func(t *jwt.Token) (any, error) { + if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"]) + } + + return []byte(j.secret), nil + }, + jwt.WithExpirationRequired(), + jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Name}), + ) +} diff --git a/internal/auth/mocks.go b/internal/auth/mocks.go index 9ad4980..c9ed3f3 100644 --- a/internal/auth/mocks.go +++ b/internal/auth/mocks.go @@ -24,8 +24,20 @@ func (a *TestAuthenticator) GenerateToken(claims jwt.Claims) (string, error) { return token.SignedString([]byte(testToken)) } +func (a *TestAuthenticator) GenerateRefreshToken(claims jwt.Claims) (string, error) { + refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, testClaims) + + return refreshToken.SignedString([]byte(testToken)) +} + func (a *TestAuthenticator) ValidateToken(token string) (*jwt.Token, error) { return jwt.Parse(token, func(token *jwt.Token) (any, error) { return []byte(testToken), nil }) } + +func (a *TestAuthenticator) ValidateRefreshToken(token string) (*jwt.Token, error) { + return jwt.Parse(token, func(token *jwt.Token) (any, error) { + return []byte(testToken), nil + }) +} diff --git a/web/.gitignore b/web/.gitignore deleted file mode 100644 index 4a7f73a..0000000 --- a/web/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Nuxt dev/build outputs -.output -.data -.nuxt -.nitro -.cache -dist - -# Node dependencies -node_modules - -# Logs -logs -*.log - -# Misc -.DS_Store -.fleet -.idea - -# Local env files -.env -.env.* -!.env.example diff --git a/web/README.md b/web/README.md deleted file mode 100644 index 25b5821..0000000 --- a/web/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Nuxt Minimal Starter - -Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more. - -## Setup - -Make sure to install dependencies: - -```bash -# npm -npm install - -# pnpm -pnpm install - -# yarn -yarn install - -# bun -bun install -``` - -## Development Server - -Start the development server on `http://localhost:3000`: - -```bash -# npm -npm run dev - -# pnpm -pnpm dev - -# yarn -yarn dev - -# bun -bun run dev -``` - -## Production - -Build the application for production: - -```bash -# npm -npm run build - -# pnpm -pnpm build - -# yarn -yarn build - -# bun -bun run build -``` - -Locally preview production build: - -```bash -# npm -npm run preview - -# pnpm -pnpm preview - -# yarn -yarn preview - -# bun -bun run preview -``` - -Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. diff --git a/web/app.vue b/web/app.vue deleted file mode 100644 index 09f935b..0000000 --- a/web/app.vue +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/web/bun.lockb b/web/bun.lockb deleted file mode 100755 index 3fb3d12..0000000 Binary files a/web/bun.lockb and /dev/null differ diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs deleted file mode 100644 index 934c3a1..0000000 --- a/web/eslint.config.mjs +++ /dev/null @@ -1,6 +0,0 @@ -// @ts-check -import withNuxt from './.nuxt/eslint.config.mjs' - -export default withNuxt( - // Your custom configs here -) diff --git a/web/nuxt.config.ts b/web/nuxt.config.ts deleted file mode 100644 index ccd8396..0000000 --- a/web/nuxt.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -// https://nuxt.com/docs/api/configuration/nuxt-config -export default defineNuxtConfig({ - compatibilityDate: '2024-11-01', - devtools: { enabled: true }, - - modules: [ - '@nuxt/content', - '@nuxt/eslint', - '@nuxt/fonts', - '@nuxt/icon', - '@nuxt/image', - '@nuxt/scripts', - '@nuxt/test-utils' - ] -}) \ No newline at end of file diff --git a/web/package.json b/web/package.json deleted file mode 100644 index 81918a0..0000000 --- a/web/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "nuxt-app", - "private": true, - "type": "module", - "scripts": { - "build": "nuxt build", - "dev": "nuxt dev", - "generate": "nuxt generate", - "preview": "nuxt preview", - "postinstall": "nuxt prepare" - }, - "dependencies": { - "@nuxt/content": "3.4.0", - "@nuxt/eslint": "1.3.0", - "@nuxt/fonts": "0.11.0", - "@nuxt/icon": "1.11.0", - "@nuxt/image": "1.10.0", - "@nuxt/scripts": "0.11.5", - "@nuxt/test-utils": "3.17.2", - "@unhead/vue": "^2.0.0-rc.8", - "eslint": "^9.0.0", - "nuxt": "^3.16.1", - "vue": "^3.5.13", - "vue-router": "^4.5.0" - } -} diff --git a/web/public/favicon.ico b/web/public/favicon.ico deleted file mode 100644 index 18993ad..0000000 Binary files a/web/public/favicon.ico and /dev/null differ diff --git a/web/public/robots.txt b/web/public/robots.txt deleted file mode 100644 index 8b13789..0000000 --- a/web/public/robots.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/server/tsconfig.json b/web/server/tsconfig.json deleted file mode 100644 index b9ed69c..0000000 --- a/web/server/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../.nuxt/tsconfig.server.json" -} diff --git a/web/tsconfig.json b/web/tsconfig.json deleted file mode 100644 index a746f2a..0000000 --- a/web/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - // https://nuxt.com/docs/guide/concepts/typescript - "extends": "./.nuxt/tsconfig.json" -}