From 31954c0c29c01fa830884f256602cfa8d09c9791 Mon Sep 17 00:00:00 2001 From: GitBluub Date: Sat, 5 Mar 2022 00:42:28 +0100 Subject: [PATCH 01/57] feat: add providerid to external tokens --- api/src/Core/User.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/Core/User.hs b/api/src/Core/User.hs index 3e2f59a..b783427 100644 --- a/api/src/Core/User.hs +++ b/api/src/Core/User.hs @@ -43,6 +43,7 @@ data ExternalToken = ExternalToken , refreshToken :: Text , expiresIn :: Int64 , service :: Service + , providerId :: Maybe Text } deriving (Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON) From 0b06eaad8ef3627a558ce4f317c1a15f146f9188 Mon Sep 17 00:00:00 2001 From: GitBluub Date: Sat, 5 Mar 2022 00:43:47 +0100 Subject: [PATCH 02/57] feat: add users.read scope to twitter --- api/src/Api/About.hs | 2 +- api/src/Api/OIDC.hs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/api/src/Api/About.hs b/api/src/Api/About.hs index e24446c..4885b2c 100644 --- a/api/src/Api/About.hs +++ b/api/src/Api/About.hs @@ -45,7 +45,7 @@ $(deriveJSON defaultOptions ''About) servicesDir :: [(FilePath, S.ByteString)] servicesDir = $(embedDir "./services/") --- servicesDir = undefined +--servicesDir = undefined about :: SockAddr -> AppM About about host = do diff --git a/api/src/Api/OIDC.hs b/api/src/Api/OIDC.hs index fd96da9..a70c63d 100644 --- a/api/src/Api/OIDC.hs +++ b/api/src/Api/OIDC.hs @@ -18,11 +18,12 @@ import Utils (UserAuth, AuthRes) import qualified Data.ByteString.Char8 as B8 import Servant.Auth.Server (AuthResult(Authenticated)) import System.Environment.MrEnv (envAsString) +import Control.Monad.Trans.Maybe (MaybeT(runMaybeT)) oauthHandler :: AuthRes -> Service -> Maybe String -> AppM NoContent oauthHandler _ _ Nothing = throwError err400 oauthHandler (Authenticated (User uid _ _)) service (Just code) = do - tokens <- liftIO $ getOauthTokens service code + tokens <- liftIO $ runMaybeT $ getOauthTokens service code case tokens of Nothing -> throwError err403 Just t -> do @@ -57,7 +58,7 @@ urlHandler Twitter (Just r) = do clientId <- liftIO $ envAsString "TWITTER_CLIENT_ID" "" backRedirect <- liftIO $ envAsString "BACK_URL" "" throwError $ err302 { errHeaders = - [("Location", B8.pack $ "https://twitter.com/i/oauth2/authorize?response_type=code&scope=like.write like.read follows.read follows.write offline.access tweet.read tweet.write&code_challenge=challenge&code_challenge_method=plain&client_id=" ++ clientId ++ "&redirect_uri=" ++ backRedirect ++ "auth/redirect" ++ "&state=" ++ r)] } + [("Location", B8.pack $ "https://twitter.com/i/oauth2/authorize?response_type=code&scope=like.write like.read follows.read follows.write offline.access tweet.read tweet.write users.read&code_challenge=challenge&code_challenge_method=plain&client_id=" ++ clientId ++ "&redirect_uri=" ++ backRedirect ++ "auth/redirect" ++ "&state=" ++ r)] } urlHandler Spotify (Just r) = do clientId <- liftIO $ envAsString "SPOTIFY_CLIENT_ID" "" backRedirect <- liftIO $ envAsString "BACK_URL" "" From 0705ca3185ec4ef2405e9369b7b7241c39088272 Mon Sep 17 00:00:00 2001 From: GitBluub Date: Sat, 5 Mar 2022 00:44:18 +0100 Subject: [PATCH 03/57] feat: worker doesn t send provider id --- api/src/Api/Worker.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/Api/Worker.hs b/api/src/Api/Worker.hs index 27fa3ed..9b2783d 100644 --- a/api/src/Api/Worker.hs +++ b/api/src/Api/Worker.hs @@ -113,7 +113,7 @@ refreshHandler :: Service -> UserId -> Maybe String -> RefreshBody -> AppM NoCon refreshHandler service uid (Just key) (RefreshBody at rt ex) = do k <- liftIO $ envAsString "WORKER_API_KEY" "" if k == key then do - updateTokens uid $ ExternalToken at rt ex service + updateTokens uid $ ExternalToken at rt ex service Nothing return NoContent else throwError err403 refreshHandler _ _ _ _ = throwError err403 From 924ec6b4251cb665fe825011a71ac9f4639fd6ce Mon Sep 17 00:00:00 2001 From: GitBluub Date: Sat, 5 Mar 2022 00:45:08 +0100 Subject: [PATCH 04/57] feat: get provider id Works for every service except anilist --- api/src/Core/OIDC.hs | 196 +++++++++++++++++++++++++++++++------------ api/src/Utils.hs | 11 ++- 2 files changed, 152 insertions(+), 55 deletions(-) diff --git a/api/src/Core/OIDC.hs b/api/src/Core/OIDC.hs index 15affb2..51222ef 100644 --- a/api/src/Core/OIDC.hs +++ b/api/src/Core/OIDC.hs @@ -6,13 +6,16 @@ import qualified Data.ByteString.Char8 as B8 import qualified Data.HashMap.Strict as HM import App (AppM) -import Core.User (ExternalToken (ExternalToken), Service (Github, Discord, Spotify, Google, Twitter, Anilist)) +import Core.User (ExternalToken (ExternalToken, accessToken, providerId), Service (Github, Discord, Spotify, Google, Twitter, Anilist)) import Data.Aeson.Types (Object, Value (String)) import Data.Text (Text, pack, unpack) import Network.HTTP.Simple (JSONException, addRequestHeader, getResponseBody, httpJSONEither, parseRequest, setRequestMethod, setRequestQueryString, setRequestBodyURLEncoded) import System.Environment.MrEnv (envAsBool, envAsInt, envAsInteger, envAsString) -import Utils (lookupObjString) +import Utils (lookupObjString, lookupObjObject, lookupObjInt) import Data.ByteString.Base64 +import Control.Monad.Trans.Maybe (MaybeT (MaybeT, runMaybeT)) +import Control.Monad.IO.Class (MonadIO(liftIO)) +import Control.Monad (MonadPlus (mzero)) data OAuth2Conf = OAuth2Conf { oauthClientId :: String , oauthClientSecret :: String @@ -32,6 +35,10 @@ tokenEndpoint code oc = , code ] +liftMaybe :: (MonadPlus m) => Maybe a -> m a +liftMaybe = maybe mzero return + + -- GITHUB getGithubConfig :: IO OAuth2Conf getGithubConfig = @@ -40,8 +47,8 @@ getGithubConfig = <*> envAsString "GITHUB_SECRET" "" <*> pure "https://github.com/login/oauth/access_token" -getGithubTokens :: String -> IO (Maybe ExternalToken) -getGithubTokens code = do +getGithubTokens :: String -> MaybeT IO ExternalToken +getGithubTokens code = MaybeT $ do gh <- getGithubConfig let endpoint = tokenEndpoint code gh request' <- parseRequest endpoint @@ -55,11 +62,31 @@ getGithubTokens code = do ] request' response <- httpJSONEither request - return $ case (getResponseBody response :: Either JSONException Object) of - Left _ -> Nothing - Right obj -> do - access <- lookupObjString obj "access_token" - Just $ ExternalToken (pack access) "" 0 Github + let (Right obj) = (getResponseBody response :: Either JSONException Object) + access <- liftMaybe $ lookupObjString obj "access_token" + let t = ExternalToken access "" 0 Github Nothing + githubId <- runMaybeT $ getGithubId t + return $ Just $ t { providerId = githubId } + +rightToMaybe :: Either a b -> Maybe b +rightToMaybe = either (const Nothing) Just + +getGithubId :: ExternalToken -> MaybeT IO Text +getGithubId t = MaybeT $ do + let endpoint = "https://api.github.com/user" + request' <- parseRequest endpoint + let request = + addRequestHeader "Authorization" (B8.pack ("token " ++ unpack (accessToken t))) $ + addRequestHeader "Accept" "application/json" $ + addRequestHeader "User-Agent" "aeris-server" + request' + response <- httpJSONEither request + print $ accessToken t + case (getResponseBody response :: Either JSONException Object) of + Left err -> return Nothing + Right obj -> case lookupObjInt obj "id" of + Just githubId -> return $ Just $ pack $ show githubId + _ -> return Nothing -- DISCORD getDiscordConfig :: IO OAuth2Conf @@ -69,8 +96,8 @@ getDiscordConfig = <*> envAsString "DISCORD_SECRET" "" <*> pure "https://discord.com/api/oauth2/token" -getDiscordTokens :: String -> IO (Maybe ExternalToken) -getDiscordTokens code = do +getDiscordTokens :: String -> MaybeT IO ExternalToken +getDiscordTokens code = MaybeT $ do cfg <- getDiscordConfig let endpoint = tokenEndpoint code cfg request' <- parseRequest endpoint @@ -86,12 +113,26 @@ getDiscordTokens code = do ] request' response <- httpJSONEither request - return $ case (getResponseBody response :: Either JSONException Object) of - Left _ -> Nothing - Right obj -> do - access <- lookupObjString obj "access_token" - refresh <- lookupObjString obj "refresh_token" - Just $ ExternalToken (pack access) (pack refresh) 0 Discord + let (Right obj) = (getResponseBody response :: Either JSONException Object) + access <- liftMaybe $ lookupObjString obj "access_token" + refresh <- liftMaybe $ lookupObjString obj "refresh_token" + let t = ExternalToken access refresh 0 Discord Nothing + discordId <- runMaybeT $ getDiscordId t + return $ Just $ t { providerId = discordId } + + +getDiscordId :: ExternalToken -> MaybeT IO Text +getDiscordId t = MaybeT $ do + let endpoint = "https://discord.com/api/users/@me" + request' <- parseRequest endpoint + let request = + addRequestHeader "Accept" "application/json" $ + addRequestHeader "Authorization" (B8.pack $ "Bearer " ++ unpack (accessToken t)) + request' + response <- httpJSONEither request + let (Right obj) = (getResponseBody response :: Either JSONException Object) + return $ lookupObjString obj "id" + -- GOOGLE getGoogleConfig :: IO OAuth2Conf @@ -101,8 +142,8 @@ getGoogleConfig = <*> envAsString "GOOGLE_SECRET" "" <*> pure "https://oauth2.googleapis.com/token" -getGoogleTokens :: String -> IO (Maybe ExternalToken) -getGoogleTokens code = do +getGoogleTokens :: String -> MaybeT IO ExternalToken +getGoogleTokens code = MaybeT $ do cfg <- getGoogleConfig let endpoint = tokenEndpoint code cfg request' <- parseRequest endpoint @@ -118,12 +159,26 @@ getGoogleTokens code = do ] request' response <- httpJSONEither request - return $ case (getResponseBody response :: Either JSONException Object) of - Left _ -> Nothing - Right obj -> do - access <- lookupObjString obj "access_token" - refresh <- lookupObjString obj "refresh_token" - Just $ ExternalToken (pack access) (pack refresh) 0 Google + let (Right obj) = (getResponseBody response :: Either JSONException Object) + access <- liftMaybe $ lookupObjString obj "access_token" + refresh <- liftMaybe $ lookupObjString obj "refresh_token" + let t = ExternalToken access refresh 0 Google Nothing + googleId <- runMaybeT $ getGoogleId t + return $ Just $ t { providerId = googleId } + +getGoogleId :: ExternalToken -> MaybeT IO Text +getGoogleId t = MaybeT $ do + let endpoint = "https://oauth2.googleapis.com/tokeninfo" + request' <- parseRequest endpoint + let request = + addRequestHeader "Accept" "application/json" $ + setRequestQueryString + [ ("access_token", Just . B8.pack . unpack $ accessToken t) + ] + request' + response <- httpJSONEither request + let (Right obj) = (getResponseBody response :: Either JSONException Object) + return $ lookupObjString obj "sub" -- SPOTIFY getSpotifyConfig :: IO OAuth2Conf @@ -133,10 +188,9 @@ getSpotifyConfig = <*> envAsString "SPOTIFY_SECRET" "" <*> pure "https://accounts.spotify.com/api/token" -getSpotifyTokens :: String -> IO (Maybe ExternalToken) -getSpotifyTokens code = do +getSpotifyTokens :: String -> MaybeT IO ExternalToken +getSpotifyTokens code = MaybeT $ do cfg <- getSpotifyConfig - let basicAuth = encodeBase64 $ B8.pack $ oauthClientId cfg ++ ":" ++ oauthClientSecret cfg let endpoint = tokenEndpoint code cfg request' <- parseRequest endpoint @@ -151,12 +205,24 @@ getSpotifyTokens code = do ] request' response <- httpJSONEither request - return $ case (getResponseBody response :: Either JSONException Object) of - Left _ -> Nothing - Right obj -> do - access <- lookupObjString obj "access_token" - refresh <- lookupObjString obj "refresh_token" - Just $ ExternalToken (pack access) (pack refresh) 0 Spotify + let (Right obj) = (getResponseBody response :: Either JSONException Object) + access <- liftMaybe $ lookupObjString obj "access_token" + refresh <- liftMaybe $ lookupObjString obj "refresh_token" + let t = ExternalToken access refresh 0 Spotify Nothing + spotifyId <- runMaybeT $ getSpotifyId t + return $ Just $ t { providerId = spotifyId } + +getSpotifyId :: ExternalToken -> MaybeT IO Text +getSpotifyId t = MaybeT $ do + let endpoint = "https://api.spotify.com/v1/me" + request' <- parseRequest endpoint + let request = + addRequestHeader "Content-Type" "application/json" $ + addRequestHeader "Authorization" (B8.pack $ "Bearer " ++ unpack (accessToken t)) + request' + response <- httpJSONEither request + let (Right obj) = (getResponseBody response :: Either JSONException Object) + return $ lookupObjString obj "id" -- TWITTER getTwitterConfig :: IO OAuth2Conf @@ -166,8 +232,8 @@ getTwitterConfig = <*> envAsString "TWITTER_SECRET" "" <*> pure "https://api.twitter.com/2/oauth2/token" -getTwitterTokens :: String -> IO (Maybe ExternalToken) -getTwitterTokens code = do +getTwitterTokens :: String -> MaybeT IO ExternalToken +getTwitterTokens code = MaybeT $ do cfg <- getTwitterConfig let basicAuth = encodeBase64 $ B8.pack $ "Basic " ++ oauthClientId cfg ++ ":" ++ oauthClientSecret cfg let endpoint = tokenEndpoint code cfg @@ -184,12 +250,26 @@ getTwitterTokens code = do ] request' response <- httpJSONEither request - return $ case (getResponseBody response :: Either JSONException Object) of - Left _ -> Nothing - Right obj -> do - access <- lookupObjString obj "access_token" - refresh <- lookupObjString obj "refresh_token" - Just $ ExternalToken (pack access) (pack refresh) 0 Twitter + let (Right obj) = (getResponseBody response :: Either JSONException Object) + access <- liftMaybe $ lookupObjString obj "access_token" + refresh <- liftMaybe $ lookupObjString obj "refresh_token" + let t = ExternalToken access refresh 0 Twitter Nothing + twitterId <- runMaybeT $ getTwitterId t + return $ Just $ t { providerId = twitterId } + +getTwitterId :: ExternalToken -> MaybeT IO Text +getTwitterId t = MaybeT $ do + let endpoint = "https://api.twitter.com/2/users/me" + request' <- parseRequest endpoint + let request = + addRequestHeader "Content-Type" "application/json" $ + addRequestHeader "Authorization" (B8.pack $ "Bearer " ++ unpack (accessToken t)) + request' + response <- httpJSONEither request + let (Right obj) = (getResponseBody response :: Either JSONException Object) + case lookupObjObject obj "data" of + Just dataBody -> return $ lookupObjString dataBody "id" + _ -> return Nothing -- ANILIST getAnilistConfig :: IO OAuth2Conf @@ -199,8 +279,8 @@ getAnilistConfig = <*> envAsString "ANILIST_SECRET" "" <*> pure "https://anilist.co/api/v2/oauth/token" -getAnilistTokens :: String -> IO (Maybe ExternalToken) -getAnilistTokens code = do +getAnilistTokens :: String -> MaybeT IO ExternalToken +getAnilistTokens code = MaybeT $ do cfg <- getAnilistConfig let endpoint = tokenEndpoint code cfg request' <- parseRequest endpoint @@ -216,18 +296,30 @@ getAnilistTokens code = do ] request' response <- httpJSONEither request - return $ case (getResponseBody response :: Either JSONException Object) of - Left _ -> Nothing - Right obj -> do - access <- lookupObjString obj "access_token" - refresh <- lookupObjString obj "refresh_token" - Just $ ExternalToken (pack access) (pack refresh) 0 Anilist - + let (Right obj) = (getResponseBody response :: Either JSONException Object) + access <- liftMaybe $ lookupObjString obj "access_token" + refresh <- liftMaybe $ lookupObjString obj "refresh_token" + let t = ExternalToken access refresh 0 Anilist Nothing + anilistId <- runMaybeT $ getAnilistId t + return $ Just $ t { providerId = anilistId } +getAnilistId :: ExternalToken -> MaybeT IO Text +getAnilistId t = MaybeT $ do + let endpoint = "https://api.twitter.com/2/users/me" + request' <- parseRequest endpoint + let request = + addRequestHeader "Content-Type" "application/json" $ + addRequestHeader "Authorization" (B8.pack $ "Bearer " ++ unpack (accessToken t)) + request' + response <- httpJSONEither request + let (Right obj) = (getResponseBody response :: Either JSONException Object) + dataBody <- liftMaybe $ lookupObjObject obj "data" + viewer <- liftMaybe $ lookupObjObject obj "Viewer" + return . Just . pack . show $ lookupObjInt viewer "id" -- General -getOauthTokens :: Service -> String -> IO (Maybe ExternalToken) +getOauthTokens :: Service -> String -> MaybeT IO ExternalToken getOauthTokens Github = getGithubTokens getOauthTokens Discord = getDiscordTokens getOauthTokens Spotify = getSpotifyTokens diff --git a/api/src/Utils.hs b/api/src/Utils.hs index 16a04be..a3565d2 100644 --- a/api/src/Utils.hs +++ b/api/src/Utils.hs @@ -25,15 +25,20 @@ import Data.Scientific ( toBoundedInteger ) mapInd :: (a -> Int -> b) -> [a] -> [b] mapInd f l = zipWith f l [0 ..] -lookupObjString :: Object -> Text -> Maybe String +lookupObjString :: Object -> Text -> Maybe Text lookupObjString obj key = case Data.HashMap.Strict.lookup key obj of - Just (String x) -> Just . unpack $ x + Just (String x) -> Just x + _ -> Nothing + +lookupObjObject :: Object -> Text -> Maybe Object +lookupObjObject obj key = case Data.HashMap.Strict.lookup key obj of + Just (Object x) -> Just x _ -> Nothing lookupObjInt :: Object -> Text -> Maybe Int64 lookupObjInt obj key = case Data.HashMap.Strict.lookup key obj of - Just (Number x) -> toBoundedInteger $ x + Just (Number x) -> toBoundedInteger x _ -> Nothing uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d From 35c947bd44302e71fe68c740186f77f1b4703584 Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 09:44:24 +0100 Subject: [PATCH 05/57] Mobile Client: Documentation deployment workflow --- .github/workflows/documentation.yaml | 64 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 73aa948..ac2308e 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -3,49 +3,47 @@ on: push: branches: - master - - workflows + - dev + workflow_dispatch: + jobs: - DeployBackDocumentation: - runs-on: ubuntu-20.04 + DeployDocumentation: + name: "Generate ${{ matrix.run_name }}'s documentation" + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - project_dir: mobile + run_name: 'Mobile client' + doc_dir: 'doc/api' + use: 'subosito/flutter-action@v1.5.3' + warm_up: flutter pub global activate dartdoc; rm -rf doc + doc_generation: dartdoc + defaults: + run: + working-directory: ${{ matrix.project_dir }} steps: - uses: actions/checkout@v2.3.4 - - name: Install stack - run: curl -sSL https://get.haskellstack.org/ | sh -s - -f - - name: Generate Haddock documentation - run: stack haddock --haddock-arguments --odir="docs" + - uses: subosito/flutter-action@v2.2.0 + with: + channel: 'dev' + if: matrix.project_dir == 'mobile' + - name: Warmup + run: ${{ matrix.warm_up }} ; ls -l + - name: Generate documentation + run: ${{ matrix.doc_generation }} - name: Deploy run: | - cd docs + cd "${{ matrix.doc_dir }}" git config --global user.email "${GITHUB_ACTOR}@github.com"; git config --global user.name "${GITHUB_ACTOR}"; git init git add -A; - git commit -m "Deploying the back-end's documentation"; + git commit -m "Deploying the ${{ matrix.run_name }}'s documentation"; git remote add origin https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@${GITHUB_REPO}; - git checkout -b documentation-back - git push --force origin documentation-back; - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_REPO: "github.com/AnonymusRaccoon/Aeris" - DeployMobileAppDocumentation: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2.3.4 - - uses: subosito/flutter-action@v1.5.3 - - name: Update Documentation - run: | - flutter pub global activate dartdoc - rm -rf doc - dartdoc - cd doc/api - git config --global user.email "${GITHUB_ACTOR}@github.com"; - git config --global user.name "${GITHUB_ACTOR}"; - git init - git add -A; - git commit -m "Deploying the mobile client documentation"; - git remote add origin https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@${GITHUB_REPO}; - git checkout -b documentation-mobile - git push --force origin documentation-mobile; + git checkout -b documentation-${{ matrix.project_dir }} + git push --force origin documentation-${{ matrix.project_dir }}; env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPO: "github.com/AnonymusRaccoon/Aeris" \ No newline at end of file From 824a446cb52c18bbb3de804fec1a65d7ab9f938c Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 09:46:16 +0100 Subject: [PATCH 06/57] Mobile Client: documentation workflow: remove non-existant branch trigger --- .github/workflows/documentation.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index ac2308e..d326c84 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -3,7 +3,6 @@ on: push: branches: - master - - dev workflow_dispatch: jobs: From 210aeab3c44e2d7e853c8ad50b2e14cfec81e476 Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 09:47:57 +0100 Subject: [PATCH 07/57] Mobile Client: documentation workflow: add branch trigger glob --- .github/workflows/documentation.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index d326c84..08376e0 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -3,6 +3,7 @@ on: push: branches: - master + - mobile_client* workflow_dispatch: jobs: From 0224b6b316d3831bc6e7b2d4739857a73a1b46a9 Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 09:49:08 +0100 Subject: [PATCH 08/57] Mobile Client: documentation workflow: add branch trigger glob --- .github/workflows/documentation.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 08376e0..ea2f0ea 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -5,7 +5,6 @@ on: - master - mobile_client* workflow_dispatch: - jobs: DeployDocumentation: name: "Generate ${{ matrix.run_name }}'s documentation" From 3ecd9772197e2ce3a9a274385c0a61b5fed46631 Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 10:10:26 +0100 Subject: [PATCH 09/57] Mobile Client Documentation: update aeris.dart + gen translations on doc gen --- mobile/lib/aeris.dart | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/mobile/lib/aeris.dart b/mobile/lib/aeris.dart index 757aa3e..a1ba65b 100644 --- a/mobile/lib/aeris.dart +++ b/mobile/lib/aeris.dart @@ -1,8 +1,45 @@ library aeris; export 'package:aeris/src/views/startup_page.dart'; - export 'package:aeris/src/widgets/overlayed_texts.dart'; - export 'package:aeris/src/widgets/background/anim_painter.dart'; export 'package:aeris/src/widgets/background/custom_animation.dart'; +export "package:aeris/src/aeris_api.dart"; +export "package:aeris/src/providers/action_catalogue_provider.dart"; +export "package:aeris/src/providers/pipelines_provider.dart"; +export "package:aeris/src/providers/services_provider.dart"; +export "package:aeris/src/models/pipeline.dart"; +export "package:aeris/src/models/action_template.dart"; +export "package:aeris/src/models/action_parameter.dart"; +export "package:aeris/src/models/reaction.dart"; +export "package:aeris/src/models/trigger.dart"; +export "package:aeris/src/models/service.dart"; +export "package:aeris/src/models/action.dart"; +export "package:aeris/src/models/pipeline_collection.dart"; +export "package:aeris/src/constants.dart"; +export "package:aeris/src/views/pipeline_detail_page.dart"; +export "package:aeris/src/views/authorization_page.dart"; +export "package:aeris/src/views/setup_action_page.dart"; +export "package:aeris/src/views/service_page.dart"; +export "package:aeris/src/views/login_page.dart"; +export "package:aeris/src/views/home_page.dart"; +export "package:aeris/src/views/create_pipeline_page.dart"; +export "package:aeris/src/views/startup_page.dart"; +export "package:aeris/src/widgets/background/anim_painter.dart"; +export "package:aeris/src/widgets/background/custom_animation.dart"; +export "package:aeris/src/widgets/background/animated_background.dart"; +export "package:aeris/src/widgets/action_card_popup_menu.dart"; +export "package:aeris/src/widgets/reorderable_reaction_cards_list.dart"; +export "package:aeris/src/widgets/aeris_page.dart"; +export "package:aeris/src/widgets/aeris_popup_menu_item.dart"; +export "package:aeris/src/widgets/warning_dialog.dart"; +export "package:aeris/src/widgets/home_page_sort_menu.dart"; +export "package:aeris/src/widgets/aeris_popup_menu.dart"; +export "package:aeris/src/widgets/aeris_card_page.dart"; +export "package:aeris/src/widgets/colored_clickable_card.dart"; +export "package:aeris/src/widgets/action_form.dart"; +export "package:aeris/src/widgets/overlayed_texts.dart"; +export "package:aeris/src/widgets/clickable_card.dart"; +export "package:aeris/src/widgets/pipeline_card.dart"; +export "package:aeris/src/widgets/action_card.dart"; +export "package:aeris/src/widgets/setup_api_route.dart"; From 61f0b2c16a9f06f5f31779780103ce20a1e881b9 Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 10:11:02 +0100 Subject: [PATCH 10/57] Mobile Client Documentation: update aeris.dart + gen translations on doc gen --- .github/workflows/documentation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index ea2f0ea..a1070b5 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -17,7 +17,7 @@ jobs: run_name: 'Mobile client' doc_dir: 'doc/api' use: 'subosito/flutter-action@v1.5.3' - warm_up: flutter pub global activate dartdoc; rm -rf doc + warm_up: flutter pub global activate dartdoc; rm -rf doc ; flutter gen-l10n doc_generation: dartdoc defaults: run: From b880029d3d7a5406512bf6a3b1c52f387e6a66e9 Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 10:15:27 +0100 Subject: [PATCH 11/57] Mobile Client Documentation: update aeris.dart + gen translations on doc gen --- .github/workflows/documentation.yaml | 1 - mobile/lib/aeris.dart | 4 ---- 2 files changed, 5 deletions(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index a1070b5..5b01e3c 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -3,7 +3,6 @@ on: push: branches: - master - - mobile_client* workflow_dispatch: jobs: DeployDocumentation: diff --git a/mobile/lib/aeris.dart b/mobile/lib/aeris.dart index a1ba65b..ea91568 100644 --- a/mobile/lib/aeris.dart +++ b/mobile/lib/aeris.dart @@ -1,9 +1,5 @@ library aeris; -export 'package:aeris/src/views/startup_page.dart'; -export 'package:aeris/src/widgets/overlayed_texts.dart'; -export 'package:aeris/src/widgets/background/anim_painter.dart'; -export 'package:aeris/src/widgets/background/custom_animation.dart'; export "package:aeris/src/aeris_api.dart"; export "package:aeris/src/providers/action_catalogue_provider.dart"; export "package:aeris/src/providers/pipelines_provider.dart"; From ae06865e8277c95f6bf90a7639706bd09a4af402 Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 10:15:54 +0100 Subject: [PATCH 12/57] Mobile Client Documentation: update aeris.dart + gen translations on doc gen --- .github/workflows/documentation.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 5b01e3c..a1070b5 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -3,6 +3,7 @@ on: push: branches: - master + - mobile_client* workflow_dispatch: jobs: DeployDocumentation: From 2fcf8942235836ea9e3e16011a46358901dedc50 Mon Sep 17 00:00:00 2001 From: Arthi-chaud Date: Sat, 5 Mar 2022 10:24:26 +0100 Subject: [PATCH 13/57] Mobile Client Documentation: update aeris.dart + gen translations on doc gen --- .github/workflows/documentation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index a1070b5..1a337d6 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -18,7 +18,7 @@ jobs: doc_dir: 'doc/api' use: 'subosito/flutter-action@v1.5.3' warm_up: flutter pub global activate dartdoc; rm -rf doc ; flutter gen-l10n - doc_generation: dartdoc + doc_generation: dartdoc; defaults: run: working-directory: ${{ matrix.project_dir }} From 72c08038f659cc559a673cc1e89eb3fe0b071b84 Mon Sep 17 00:00:00 2001 From: GitBluub Date: Sat, 5 Mar 2022 12:15:02 +0100 Subject: [PATCH 14/57] feat: anilist id --- api/src/Core/OIDC.hs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/api/src/Core/OIDC.hs b/api/src/Core/OIDC.hs index 51222ef..5ed8538 100644 --- a/api/src/Core/OIDC.hs +++ b/api/src/Core/OIDC.hs @@ -9,13 +9,14 @@ import App (AppM) import Core.User (ExternalToken (ExternalToken, accessToken, providerId), Service (Github, Discord, Spotify, Google, Twitter, Anilist)) import Data.Aeson.Types (Object, Value (String)) import Data.Text (Text, pack, unpack) -import Network.HTTP.Simple (JSONException, addRequestHeader, getResponseBody, httpJSONEither, parseRequest, setRequestMethod, setRequestQueryString, setRequestBodyURLEncoded) +import Network.HTTP.Simple (JSONException, addRequestHeader, getResponseBody, httpJSONEither, parseRequest, setRequestMethod, setRequestQueryString, setRequestBodyURLEncoded, setRequestBodyJSON, setRequestBodyLBS) import System.Environment.MrEnv (envAsBool, envAsInt, envAsInteger, envAsString) import Utils (lookupObjString, lookupObjObject, lookupObjInt) import Data.ByteString.Base64 import Control.Monad.Trans.Maybe (MaybeT (MaybeT, runMaybeT)) import Control.Monad.IO.Class (MonadIO(liftIO)) import Control.Monad (MonadPlus (mzero)) +import Data.Aeson (decode) data OAuth2Conf = OAuth2Conf { oauthClientId :: String , oauthClientSecret :: String @@ -306,17 +307,26 @@ getAnilistTokens code = MaybeT $ do getAnilistId :: ExternalToken -> MaybeT IO Text getAnilistId t = MaybeT $ do - let endpoint = "https://api.twitter.com/2/users/me" + let endpoint = "https://graphql.anilist.co" request' <- parseRequest endpoint + let query = (decode "{Viewer {id,}}" :: Maybe Object) let request = addRequestHeader "Content-Type" "application/json" $ - addRequestHeader "Authorization" (B8.pack $ "Bearer " ++ unpack (accessToken t)) + addRequestHeader "Authorization" (B8.pack $ "Bearer " ++ unpack (accessToken t)) $ + addRequestHeader "User-Agent" "aeris-server" $ + setRequestMethod "POST" $ + setRequestBodyLBS "{\"query\": \"{Viewer {id}}\"}" request' response <- httpJSONEither request let (Right obj) = (getResponseBody response :: Either JSONException Object) - dataBody <- liftMaybe $ lookupObjObject obj "data" - viewer <- liftMaybe $ lookupObjObject obj "Viewer" - return . Just . pack . show $ lookupObjInt viewer "id" + case lookupObjObject obj "data" of + Just dataBody -> case liftMaybe $ lookupObjObject dataBody "Viewer" of + Just viewer -> case lookupObjInt viewer "id" of + Just anilistId -> return . Just . pack . show $ anilistId + _ -> return Nothing + _ -> return Nothing + _ -> return Nothing + -- General getOauthTokens :: Service -> String -> MaybeT IO ExternalToken From 63f446d3ed08e2b9bcb016358ac8af6c3bcb563a Mon Sep 17 00:00:00 2001 From: GitBluub Date: Sat, 5 Mar 2022 16:21:51 +0100 Subject: [PATCH 15/57] feat: signin route --- api/src/Api/Auth.hs | 48 +++++++++++++++++++++++++++----------- api/src/Api/OIDC.hs | 11 +++++---- api/src/Repository/User.hs | 21 +++++++++++++++-- api/src/Utils.hs | 7 ++++-- 4 files changed, 65 insertions(+), 22 deletions(-) diff --git a/api/src/Api/Auth.hs b/api/src/Api/Auth.hs index c2d4a5c..dab4bb6 100644 --- a/api/src/Api/Auth.hs +++ b/api/src/Api/Auth.hs @@ -18,12 +18,16 @@ import Servant ( Post, ReqBody, err401, + err400, + err403, throwError, type (:<|>) (..), - type (:>), + type (:>), Capture, QueryParam ) import Control.Monad.IO.Class (liftIO) +import Control.Monad.Trans.Maybe (MaybeT(runMaybeT)) +import Core.OIDC ( getOauthTokens ) import Data.Aeson (FromJSON, ToJSON) import Db.User (User', UserDB (UserDB), password, toUser) import GHC.Generics (Generic) @@ -34,10 +38,10 @@ import Servant.Server.Generic (AsServerT) import Data.ByteString.Lazy.Char8 ( unpack ) import Api.OIDC (OauthAPI, oauth) import App (AppM) -import Core.User (User, UserId (UserId)) +import Core.User (User, UserId (UserId), Service) import Data.Text (pack) import Password (hashPassword'', toPassword, validatePassword') -import Repository (createUser, getUserByName') +import Repository (createUser, getUserByName', getUserByToken) import Utils (UserAuth, AuthRes) data LoginUser = LoginUser @@ -57,15 +61,16 @@ newtype LoginResponse = LoginResponse } deriving (Eq, Show, Read, Generic) + +instance ToJSON LoginResponse +instance FromJSON LoginResponse + instance ToJSON LoginUser instance FromJSON LoginUser instance ToJSON SignupUser instance FromJSON SignupUser -instance ToJSON LoginResponse -instance FromJSON LoginResponse - type Protected = "me" :> Get '[JSON] User @@ -80,6 +85,10 @@ type Unprotected = :<|> "signup" :> ReqBody '[JSON] SignupUser :> Post '[JSON] NoContent + :<|> Capture "service" Service :> "signin" + :> QueryParam "code" String + :> Post '[JSON] LoginResponse + loginHandler :: CookieSettings -> @@ -95,11 +104,23 @@ loginHandler cs jwts (LoginUser username p) = do case etoken of Left e -> throwError err401 Right v -> return $ LoginResponse $ unpack v - {--mApplyCookies <- liftIO $ acceptLogin cs jwts (toUser usr) - case mApplyCookies of - Nothing -> throwError err401 - Just applyCookies -> return $ applyCookies NoContent - --}else throwError err401 + else throwError err401 + + +loginOauthHandler :: JWTSettings -> Service -> Maybe String -> AppM LoginResponse +loginOauthHandler jwts _ Nothing = throwError err400 +loginOauthHandler jwts service (Just code) = do + tokens <- liftIO $ runMaybeT $ getOauthTokens service code + case tokens of + Nothing -> throwError err403 + Just t -> do + user <- getUserByToken t + etoken <- liftIO $ makeJWT (toUser user) jwts Nothing + case etoken of + Left e -> throwError err401 + Right v -> return $ LoginResponse $ unpack v + + signupHandler :: SignupUser -> @@ -111,8 +132,9 @@ signupHandler (SignupUser name p) = do unprotected :: CookieSettings -> JWTSettings -> ServerT Unprotected AppM unprotected cs jwts = - loginHandler cs jwts - :<|> signupHandler + loginHandler cs jwts + :<|> signupHandler + :<|> loginOauthHandler jwts data AuthAPI mode = AuthAPI { protectedApi :: mode :- UserAuth :> Protected diff --git a/api/src/Api/OIDC.hs b/api/src/Api/OIDC.hs index a70c63d..43d9880 100644 --- a/api/src/Api/OIDC.hs +++ b/api/src/Api/OIDC.hs @@ -8,17 +8,18 @@ module Api.OIDC where import App (AppM) import Control.Monad.IO.Class (liftIO) import Core.User (ExternalToken (ExternalToken, service), Service (Github, Spotify, Twitter, Google, Anilist, Discord), UserId (UserId), User (User)) -import Data.Text (pack) +import Data.Text (pack, unpack) import Core.OIDC ( getOauthTokens ) import Repository.User (updateTokens, getTokensByUserId, delTokens) -import Servant (Capture, Get, GetNoContent, JSON, NoContent (NoContent), QueryParam, ServerT, err400, throwError, type (:<|>) ((:<|>)), type (:>), err401, err403, ServerError (errHeaders), err302, Delete) +import Servant (Capture, Get, GetNoContent, JSON, NoContent (NoContent), QueryParam, ServerT, err400, throwError, type (:<|>) ((:<|>)), type (:>), err401, err403, ServerError (errHeaders), err302, Delete, Post) import Servant.API.Generic (type (:-)) import Servant.Server.Generic (AsServerT) import Utils (UserAuth, AuthRes) import qualified Data.ByteString.Char8 as B8 -import Servant.Auth.Server (AuthResult(Authenticated)) +import Servant.Auth.Server (AuthResult(Authenticated), makeJWT) import System.Environment.MrEnv (envAsString) import Control.Monad.Trans.Maybe (MaybeT(runMaybeT)) +import Db.User (toUser) oauthHandler :: AuthRes -> Service -> Maybe String -> AppM NoContent oauthHandler _ _ Nothing = throwError err400 @@ -89,10 +90,10 @@ type OauthAPI = UserAuth :> Capture "service" Service :> QueryParam "code" Strin :<|> Capture "service" Service :> "url" :> QueryParam "redirect_uri" String :> Get '[JSON] NoContent :<|> UserAuth :> "services" :> Get '[JSON] [String] :<|> "redirect" :> QueryParam "code" String :> QueryParam "state" String :> Get '[JSON] NoContent - + oauth :: ServerT OauthAPI AppM oauth = oauthHandler :<|> oauthDelHandler :<|> urlHandler :<|> servicesHandler - :<|> redirectHandler + :<|> redirectHandler \ No newline at end of file diff --git a/api/src/Repository/User.hs b/api/src/Repository/User.hs index ce3ef9b..a3ba3fe 100644 --- a/api/src/Repository/User.hs +++ b/api/src/Repository/User.hs @@ -1,12 +1,14 @@ module Repository.User where import App (AppM) -import Core.User (ExternalToken, UserId, Service) +import Core.User (ExternalToken (service, providerId), UserId, Service) import Data.Text (Text) -import Db.User (User', getUserByName, getUserTokensById, insertUser, selectAllUser, updateUserTokens, getUserById, updateDelTokens) +import Db.User (User', getUserByName, getUserTokensById, insertUser, selectAllUser, updateUserTokens, getUserById, updateDelTokens, UserDB (externalTokens)) import Rel8 (insert, select, update, limit, lit) import Repository.Utils (runQuery) import Data.Int (Int64) +import Data.List (find) +import Servant (err401, throwError) users :: AppM [User'] users = runQuery (select selectAllUser) @@ -19,6 +21,21 @@ getUserById' uid = do res <- runQuery (select $ limit 1 $ getUserById (lit uid)) return $ head res +getUserByToken :: ExternalToken -> AppM User' +getUserByToken t = do + users' <- users + case find findByToken users' of + Nothing -> throwError err401 + Just x -> return x + where + findByToken :: User' -> Bool + findByToken usr = do + let userTokens = externalTokens usr + case find (\tok -> service tok == service t) userTokens of + Nothing -> False + Just tok -> providerId tok == providerId t + + createUser :: User' -> AppM [UserId] createUser user = runQuery (insert $ insertUser user) diff --git a/api/src/Utils.hs b/api/src/Utils.hs index a3565d2..bb6ab89 100644 --- a/api/src/Utils.hs +++ b/api/src/Utils.hs @@ -3,6 +3,7 @@ {-# OPTIONS_GHC -Wno-deferred-out-of-scope-variables #-} {-# LANGUAGE FlexibleInstances #-} + module Utils where import Data.Aeson.Types (Value (String), Object) @@ -18,9 +19,10 @@ import Db.Pipeline (Pipeline (Pipeline), PipelineId (PipelineId), pipelineLastTr import Core.Pipeline (PipelineParams (PipelineParams)) import Data.Time (UTCTime (UTCTime), fromGregorian, secondsToDiffTime) import Data.Default (Default, def) -import Data.Aeson (Value(Number, Object), decode) +import Data.Aeson (Value(Number, Object), decode, ToJSON, FromJSON) import Data.Int (Int64) import Data.Scientific ( toBoundedInteger ) +import GHC.Generics (Generic) mapInd :: (a -> Int -> b) -> [a] -> [b] mapInd f l = zipWith f l [0 ..] @@ -60,4 +62,5 @@ instance Default (Pipeline Identity) where } type UserAuth = Servant.Auth.Server.Auth '[JWT] User -type AuthRes = Servant.Auth.Server.AuthResult User \ No newline at end of file +type AuthRes = Servant.Auth.Server.AuthResult User + From 85c1e7dc4c61e6cc26c78ea7115a4f02746591be Mon Sep 17 00:00:00 2001 From: GitBluub Date: Sat, 5 Mar 2022 18:27:13 +0100 Subject: [PATCH 16/57] start: helm aeris chart --- k8s/aeris/.helmignore | 23 ++++++++++++ k8s/aeris/Chart.yaml | 24 +++++++++++++ k8s/aeris/values.yaml | 82 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 k8s/aeris/.helmignore create mode 100644 k8s/aeris/Chart.yaml create mode 100644 k8s/aeris/values.yaml diff --git a/k8s/aeris/.helmignore b/k8s/aeris/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/k8s/aeris/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/k8s/aeris/Chart.yaml b/k8s/aeris/Chart.yaml new file mode 100644 index 0000000..3624076 --- /dev/null +++ b/k8s/aeris/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: aeris +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/k8s/aeris/values.yaml b/k8s/aeris/values.yaml new file mode 100644 index 0000000..22fc3ad --- /dev/null +++ b/k8s/aeris/values.yaml @@ -0,0 +1,82 @@ +# Default values for aeris. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} From 96cfcd656bd8f4adccc59951a3f1717ce0a1670b Mon Sep 17 00:00:00 2001 From: GitBluub Date: Sat, 5 Mar 2022 19:00:07 +0100 Subject: [PATCH 17/57] start: default files --- k8s/aeris/templates/back.deployment.yaml | 0 k8s/aeris/templates/back.service.yaml | 0 k8s/aeris/templates/front.deployment.yaml | 0 k8s/aeris/templates/front.service.yaml | 0 k8s/aeris/templates/postgres.configmap.yaml | 0 k8s/aeris/templates/postgres.deployment.yaml | 0 k8s/aeris/templates/postgres.secret.yaml | 0 k8s/aeris/templates/postgres.service.yaml | 0 k8s/aeris/templates/worker.deployment.yaml | 0 k8s/aeris/templates/worker.service.yaml | 0 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 k8s/aeris/templates/back.deployment.yaml create mode 100644 k8s/aeris/templates/back.service.yaml create mode 100644 k8s/aeris/templates/front.deployment.yaml create mode 100644 k8s/aeris/templates/front.service.yaml create mode 100644 k8s/aeris/templates/postgres.configmap.yaml create mode 100644 k8s/aeris/templates/postgres.deployment.yaml create mode 100644 k8s/aeris/templates/postgres.secret.yaml create mode 100644 k8s/aeris/templates/postgres.service.yaml create mode 100644 k8s/aeris/templates/worker.deployment.yaml create mode 100644 k8s/aeris/templates/worker.service.yaml diff --git a/k8s/aeris/templates/back.deployment.yaml b/k8s/aeris/templates/back.deployment.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/back.service.yaml b/k8s/aeris/templates/back.service.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/front.deployment.yaml b/k8s/aeris/templates/front.deployment.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/front.service.yaml b/k8s/aeris/templates/front.service.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/postgres.configmap.yaml b/k8s/aeris/templates/postgres.configmap.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/postgres.deployment.yaml b/k8s/aeris/templates/postgres.deployment.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/postgres.secret.yaml b/k8s/aeris/templates/postgres.secret.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/postgres.service.yaml b/k8s/aeris/templates/postgres.service.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/worker.deployment.yaml b/k8s/aeris/templates/worker.deployment.yaml new file mode 100644 index 0000000..e69de29 diff --git a/k8s/aeris/templates/worker.service.yaml b/k8s/aeris/templates/worker.service.yaml new file mode 100644 index 0000000..e69de29 From 9e71e1de0b7e0d787619d4480d8f6860f54bbf54 Mon Sep 17 00:00:00 2001 From: 0Nom4D Date: Sat, 5 Mar 2022 19:31:32 +0100 Subject: [PATCH 18/57] Aeris : feat/oauth-sign - Exchanging Files cause of Spotify Error --- .../components/Authorizations/ServiceAuth.tsx | 23 +++++++++++++++++ web-app/src/index.tsx | 19 ++++++++------ web-app/src/pages/Login/LoginPage.tsx | 25 +++++++++++++++++-- 3 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 web-app/src/components/Authorizations/ServiceAuth.tsx diff --git a/web-app/src/components/Authorizations/ServiceAuth.tsx b/web-app/src/components/Authorizations/ServiceAuth.tsx new file mode 100644 index 0000000..28eed19 --- /dev/null +++ b/web-app/src/components/Authorizations/ServiceAuth.tsx @@ -0,0 +1,23 @@ +import { useNavigate, useSearchParams } from "react-router-dom"; +import { sendServiceAuthToken } from "../../utils/utils"; +import { useEffect } from "react"; + +interface ServiceAuthProps { + service: string + redirect_uri: string + navigate_to: string +} + +export default function ServiceAuth({ service, redirect_uri, navigate_to }: ServiceAuthProps) { + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + const authCode = searchParams.get("code") as string; + + useEffect(() => { + sendServiceAuthToken(authCode, "/auth/" + service, `${window.location.origin}/${redirect_uri}`).then((ok) => { + navigate(navigate_to); + }) + }, []); + + return
; +} \ No newline at end of file diff --git a/web-app/src/index.tsx b/web-app/src/index.tsx index 236f033..ddf7bc1 100644 --- a/web-app/src/index.tsx +++ b/web-app/src/index.tsx @@ -1,8 +1,9 @@ -import { StrictMode } from "react"; +import {StrictMode, useState} from "react"; import ReactDOM from "react-dom"; import "./App.css"; import App from "./App"; +import ServiceAuth from "./components/Authorizations/ServiceAuth"; import GithubAuth from "./components/Authorizations/GithubAuth"; import SpotifyAuth from "./components/Authorizations/SpotifyAuth"; import GoogleAuth from "./components/Authorizations/YoutubeAuth"; @@ -15,11 +16,15 @@ import PipelinePage from "./pages/HomePage"; import { ThemeProvider } from "@mui/material"; import theme from "./Aeris.theme"; +import {AppServices} from "./utils/globals"; +import {AppServiceType} from "./utils/types"; /** * Creates the routing tree. */ function AerisRouter() { + const [possibleServices, setServices] = useState>(AppServices) + return (
@@ -29,12 +34,12 @@ function AerisRouter() { } /> } /> } /> - } /> - } /> - } /> - } /> - } /> - } /> + {possibleServices.map((elem, index) => { + return (} />); + })} + {/*{possibleServices.map((elem, index) => {*/} + {/* return (} />);*/} + {/*})}*/} diff --git a/web-app/src/pages/Login/LoginPage.tsx b/web-app/src/pages/Login/LoginPage.tsx index 325d516..07e08fc 100644 --- a/web-app/src/pages/Login/LoginPage.tsx +++ b/web-app/src/pages/Login/LoginPage.tsx @@ -4,9 +4,9 @@ import { makeStyles, Theme } from "@material-ui/core/styles"; import { useNavigate, Link as RouterLink } from "react-router-dom"; import { AccountCircle, Cookie, Lock } from "@mui/icons-material"; -import { InputAdornment } from "@mui/material"; +import {CardMedia, Divider, InputAdornment, Typography} from "@mui/material"; -import { API_ROUTE } from "../../utils/globals"; +import {API_ROUTE, AppServices} from "../../utils/globals"; import CardContent from "@material-ui/core/CardContent"; import CardActions from "@material-ui/core/CardActions"; @@ -20,6 +20,7 @@ import { setCookie, getCookie } from "../../utils/utils"; import { useTranslation } from "react-i18next"; import '../../i18n/config'; +import {AppServiceType} from "../../utils/types"; const useStyles = makeStyles((theme: Theme) => ({ container: { @@ -91,6 +92,7 @@ export default function AuthComponent() { const { t } = useTranslation(); const classes = useStyles(); const navigate = useNavigate(); + const [servicesData, setServicesData] = useState>(AppServices); const [authData, setAuthData] = useState({ username: "", password: "", @@ -253,6 +255,25 @@ export default function AuthComponent() { {authData.authMode === "login" ? t('signUp') : t('connectToAeris')} + + + Or you can sign up with this services: + + + {servicesData.map((elem, index) => { + if (elem.uid === "utils") + return (
); + return ( + + ); + })} +
From e3a94aa17f462049d328779e859accf0f818263b Mon Sep 17 00:00:00 2001 From: 0Nom4D Date: Sat, 5 Mar 2022 22:35:04 +0100 Subject: [PATCH 19/57] Aeris : feat/oauth-signin - Adding Sign In with Services --- .../components/Authorizations/AnilistAuth.tsx | 18 ------------- .../components/Authorizations/DiscordAuth.tsx | 19 ------------- .../components/Authorizations/GithubAuth.tsx | 18 ------------- .../components/Authorizations/ServiceAuth.tsx | 5 ++-- .../Authorizations/ServiceSignIn.tsx | 27 +++++++++++++++++++ .../components/Authorizations/SpotifyAuth.tsx | 19 ------------- .../components/Authorizations/TwitterAuth.tsx | 19 ------------- .../components/Authorizations/YoutubeAuth.tsx | 19 ------------- web-app/src/index.tsx | 15 ++++------- web-app/src/pages/Login/LoginPage.tsx | 2 +- web-app/src/utils/globals.tsx | 18 +++++++++++-- web-app/src/utils/types.tsx | 2 ++ web-app/src/utils/utils.tsx | 20 ++++++++++++++ 13 files changed, 74 insertions(+), 127 deletions(-) delete mode 100644 web-app/src/components/Authorizations/AnilistAuth.tsx delete mode 100644 web-app/src/components/Authorizations/DiscordAuth.tsx delete mode 100644 web-app/src/components/Authorizations/GithubAuth.tsx create mode 100644 web-app/src/components/Authorizations/ServiceSignIn.tsx delete mode 100644 web-app/src/components/Authorizations/SpotifyAuth.tsx delete mode 100644 web-app/src/components/Authorizations/TwitterAuth.tsx delete mode 100644 web-app/src/components/Authorizations/YoutubeAuth.tsx diff --git a/web-app/src/components/Authorizations/AnilistAuth.tsx b/web-app/src/components/Authorizations/AnilistAuth.tsx deleted file mode 100644 index 278e038..0000000 --- a/web-app/src/components/Authorizations/AnilistAuth.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { getCookie, sendServiceAuthToken } from "../../utils/utils"; -import { useNavigate, useSearchParams } from "react-router-dom"; -import React, { useEffect } from "react"; -import { API_ROUTE } from "../../utils/globals"; - -export default function Anilist() { - const [searchParams, setSearchParams] = useSearchParams(); - const navigate = useNavigate(); - const authCode = searchParams.get("code") as string; - - useEffect(() => { - sendServiceAuthToken(authCode, "/auth/anilist", `${window.location.origin}/authorization/anilist`).then((ok) => { - navigate('/pipelines'); - }); - }, []); - - return
; -} diff --git a/web-app/src/components/Authorizations/DiscordAuth.tsx b/web-app/src/components/Authorizations/DiscordAuth.tsx deleted file mode 100644 index c22fb17..0000000 --- a/web-app/src/components/Authorizations/DiscordAuth.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { getCookie, sendServiceAuthToken } from "../../utils/utils"; -import { useNavigate, useSearchParams } from "react-router-dom"; -import { useEffect } from "react"; -import { API_ROUTE } from "../../utils/globals"; - -export default function DiscordAuth() { - const [searchParams, setSearchParams] = useSearchParams(); - const navigate = useNavigate(); - - const authToken = searchParams.get("code") as string; - - useEffect(() => { - sendServiceAuthToken(authToken, "/auth/discord", `${window.location.origin}/authorization/discord`).then((ok) => { - navigate('/pipelines'); - }); - }, []); - - return
; -} diff --git a/web-app/src/components/Authorizations/GithubAuth.tsx b/web-app/src/components/Authorizations/GithubAuth.tsx deleted file mode 100644 index e9c2757..0000000 --- a/web-app/src/components/Authorizations/GithubAuth.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { getCookie, sendServiceAuthToken } from "../../utils/utils"; -import { useNavigate, useSearchParams } from "react-router-dom"; -import { useEffect } from "react"; -import { API_ROUTE } from "../../utils/globals"; - -export default function GithubAuth() { - const [searchParams, setSearchParams] = useSearchParams(); - const navigate = useNavigate(); - const authCode = searchParams.get("code") as string; - - useEffect(() => { - sendServiceAuthToken(authCode, "/auth/github", `${window.location.origin}/authorization/github`).then((ok) => { - navigate('/pipelines'); - }); - }, []); - - return
; -} diff --git a/web-app/src/components/Authorizations/ServiceAuth.tsx b/web-app/src/components/Authorizations/ServiceAuth.tsx index 28eed19..04732d2 100644 --- a/web-app/src/components/Authorizations/ServiceAuth.tsx +++ b/web-app/src/components/Authorizations/ServiceAuth.tsx @@ -4,17 +4,18 @@ import { useEffect } from "react"; interface ServiceAuthProps { service: string + endpoint: string redirect_uri: string navigate_to: string } -export default function ServiceAuth({ service, redirect_uri, navigate_to }: ServiceAuthProps) { +export default function ServiceAuth({ service, endpoint, redirect_uri, navigate_to }: ServiceAuthProps) { const [searchParams] = useSearchParams(); const navigate = useNavigate(); const authCode = searchParams.get("code") as string; useEffect(() => { - sendServiceAuthToken(authCode, "/auth/" + service, `${window.location.origin}/${redirect_uri}`).then((ok) => { + sendServiceAuthToken(authCode, "/auth/" + service + endpoint, `${window.location.origin}/${redirect_uri}`).then((ok) => { navigate(navigate_to); }) }, []); diff --git a/web-app/src/components/Authorizations/ServiceSignIn.tsx b/web-app/src/components/Authorizations/ServiceSignIn.tsx new file mode 100644 index 0000000..b82f243 --- /dev/null +++ b/web-app/src/components/Authorizations/ServiceSignIn.tsx @@ -0,0 +1,27 @@ +import { useNavigate, useSearchParams } from "react-router-dom"; +import {sendServiceAuthToken, setCookie, signInService} from "../../utils/utils"; +import { useEffect } from "react"; + +interface ServiceAuthProps { + service: string + endpoint: string + redirect_uri: string + navigate_to: string +} + +export default function ServiceSignIn({ service, endpoint, redirect_uri, navigate_to }: ServiceAuthProps) { + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + const authCode = searchParams.get("code") as string; + + useEffect(() => { + signInService(authCode, "/auth/" + service + endpoint, `${window.location.origin}/${redirect_uri}`).then((ok) => { + if (ok) + navigate(navigate_to); + else + console.warn('An error occurred when signing in with a service.'); + }) + }, []); + + return
; +} \ No newline at end of file diff --git a/web-app/src/components/Authorizations/SpotifyAuth.tsx b/web-app/src/components/Authorizations/SpotifyAuth.tsx deleted file mode 100644 index 69ce0d7..0000000 --- a/web-app/src/components/Authorizations/SpotifyAuth.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { getCookie, sendServiceAuthToken } from "../../utils/utils"; -import { useNavigate, useSearchParams } from "react-router-dom"; -import { useEffect } from "react"; -import { API_ROUTE } from "../../utils/globals"; - -export default function SpotifyAuth() { - const [searchParams, setSearchParams] = useSearchParams(); - const navigate = useNavigate(); - - const authCode = searchParams.get("code") as string; - - useEffect(() => { - sendServiceAuthToken(authCode, "/auth/spotify", `${window.location.origin}/authorization/spotify`).then((ok) => { - navigate('/pipelines'); - }); - }, []); - - return
; -} diff --git a/web-app/src/components/Authorizations/TwitterAuth.tsx b/web-app/src/components/Authorizations/TwitterAuth.tsx deleted file mode 100644 index c606adf..0000000 --- a/web-app/src/components/Authorizations/TwitterAuth.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { getCookie, sendServiceAuthToken } from "../../utils/utils"; -import { useNavigate, useSearchParams } from "react-router-dom"; -import { useEffect } from "react"; -import { API_ROUTE } from "../../utils/globals"; - -export default function TwitterAuth() { - const [searchParams, setSearchParams] = useSearchParams(); - const navigate = useNavigate(); - - const authCode = searchParams.get("code") as string; - - useEffect(() => { - sendServiceAuthToken(authCode, "/auth/twitter", `${window.location.origin}/authorization/twitter`).then((ok) => { - navigate('/pipelines'); - }); - }, []); - - return
; -} diff --git a/web-app/src/components/Authorizations/YoutubeAuth.tsx b/web-app/src/components/Authorizations/YoutubeAuth.tsx deleted file mode 100644 index e81da32..0000000 --- a/web-app/src/components/Authorizations/YoutubeAuth.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { getCookie, sendServiceAuthToken } from "../../utils/utils"; -import { useNavigate, useSearchParams } from "react-router-dom"; -import { useEffect } from "react"; -import { API_ROUTE } from "../../utils/globals"; - -export default function GoogleAuth() { - const [searchParams, setSearchParams] = useSearchParams(); - const navigate = useNavigate(); - - const authCode = searchParams.get("code") as string; - - useEffect(() => { - sendServiceAuthToken(authCode, "/auth/google", `${window.location.origin}/authorization/google`).then((ok) => { - navigate('/pipelines'); - }); - }, []); - - return
; -} diff --git a/web-app/src/index.tsx b/web-app/src/index.tsx index ddf7bc1..eb57d37 100644 --- a/web-app/src/index.tsx +++ b/web-app/src/index.tsx @@ -4,12 +4,6 @@ import "./App.css"; import App from "./App"; import ServiceAuth from "./components/Authorizations/ServiceAuth"; -import GithubAuth from "./components/Authorizations/GithubAuth"; -import SpotifyAuth from "./components/Authorizations/SpotifyAuth"; -import GoogleAuth from "./components/Authorizations/YoutubeAuth"; -import TwitterAuth from "./components/Authorizations/TwitterAuth"; -import DiscordAuth from "./components/Authorizations/DiscordAuth"; -import AnilistAuth from "./components/Authorizations/AnilistAuth"; import { BrowserRouter, Routes, Route } from "react-router-dom"; import AuthComponent from "./pages/Login/LoginPage"; import PipelinePage from "./pages/HomePage"; @@ -18,6 +12,7 @@ import { ThemeProvider } from "@mui/material"; import theme from "./Aeris.theme"; import {AppServices} from "./utils/globals"; import {AppServiceType} from "./utils/types"; +import ServiceSignIn from "./components/Authorizations/ServiceSignIn"; /** * Creates the routing tree. @@ -35,11 +30,11 @@ function AerisRouter() { } /> } /> {possibleServices.map((elem, index) => { - return (} />); + return (} />); + })} + {possibleServices.map((elem, index) => { + return (} />); })} - {/*{possibleServices.map((elem, index) => {*/} - {/* return (} />);*/} - {/*})}*/} diff --git a/web-app/src/pages/Login/LoginPage.tsx b/web-app/src/pages/Login/LoginPage.tsx index 07e08fc..03935e2 100644 --- a/web-app/src/pages/Login/LoginPage.tsx +++ b/web-app/src/pages/Login/LoginPage.tsx @@ -265,7 +265,7 @@ export default function AuthComponent() { return (
); return ( + + + +
+ ); +} \ No newline at end of file diff --git a/web-app/src/index.tsx b/web-app/src/index.tsx index eb57d37..c3eb0e3 100644 --- a/web-app/src/index.tsx +++ b/web-app/src/index.tsx @@ -13,6 +13,7 @@ import theme from "./Aeris.theme"; import {AppServices} from "./utils/globals"; import {AppServiceType} from "./utils/types"; import ServiceSignIn from "./components/Authorizations/ServiceSignIn"; +import ServiceSignUp from "./components/Authorizations/ServiceSignUp"; /** * Creates the routing tree. @@ -35,6 +36,9 @@ function AerisRouter() { {possibleServices.map((elem, index) => { return (} />); })} + {possibleServices.map((elem, index) => { + return (} />); + })} diff --git a/web-app/src/pages/Login/LoginPage.tsx b/web-app/src/pages/Login/LoginPage.tsx index 03935e2..bec316d 100644 --- a/web-app/src/pages/Login/LoginPage.tsx +++ b/web-app/src/pages/Login/LoginPage.tsx @@ -265,7 +265,9 @@ export default function AuthComponent() { return (
); return (