From 39fd416b4aa9e1986c607d396efc0a0fb24c136b Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sun, 12 Jul 2020 18:48:12 +0200 Subject: [PATCH] Use generated client in web interface --- .drone.yml | 60 +-- .../net/friedl/fling/FlingConfiguration.java | 4 +- .../security/FlingWebSecurityConfigurer.java | 6 +- .../JwtAuthenticationFilter.java | 8 +- .../fling/service/AuthenticationService.java | 3 + .../fling/service/AuthorizationService.java | 2 + .../friedl/fling/service/FlingService.java | 2 + .../src/main/resources/application-local.yml | 4 +- .../service/AuthenticationServiceTest.java | 13 + .../service/AuthorizationServiceTest.java | 13 + .../fling/service/FlingServiceTest.java | 9 + web/fling/.env | 2 +- web/fling/.env.development.local | 2 +- web/fling/package-lock.json | 454 +++++++++--------- web/fling/package.json | 3 +- web/fling/src/components/admin/Login.jsx | 121 ++--- web/fling/src/util/fc.js | 25 + 17 files changed, 385 insertions(+), 346 deletions(-) create mode 100644 web/fling/src/util/fc.js diff --git a/.drone.yml b/.drone.yml index 7634c87..4989620 100644 --- a/.drone.yml +++ b/.drone.yml @@ -26,6 +26,36 @@ steps: - java -jar fling-0.1.0-SNAPSHOT.jar detach: true +- name: generate-clients + image: alpine + environment: + NEXUS_USER: + from_secret: nexus_user + NEXUS_PASSWORD: + from_secret: nexus_password + commands: + - apk add --update --no-cache openjdk11 npm + - sleep 20 + - npm install @openapitools/openapi-generator-cli -g + # Python client + - openapi-generator generate + -i http://runservice:8080/v3/api-docs + -g python + -o flingclient.py + --enable-post-process-file + # JavaScript client + - openapi-generator generate + -i http://runservice:8080/v3/api-docs + -g javascript + --additional-properties projectName=@fling/flingclient,usePromises=true,npmRepository=https://nexus.friedl.net/repository/npm-private/ + -o flingclient.js + --enable-post-process-file + - cd flingclient.js && npm install && npm run build + - echo "https://nexus.friedl.net/repository/npm-private/" >> .npmrc + - echo -n "_auth=" >> .npmrc && echo -n "$NEXUS_USER:$NEXUS_PASSWORD" | base64 >> .npmrc + - echo "email=dev@friedl.net" >> .npmrc + - npm publish + - name: build-web image: node:latest volumes: @@ -60,36 +90,6 @@ steps: build_args: - VERSION=0.1.0-snapshot -- name: generate-clients - image: alpine - environment: - NEXUS_USER: - from_secret: nexus_user - NEXUS_PASSWORD: - from_secret: nexus_password - commands: - - apk add --update --no-cache openjdk11 npm - - sleep 20 - - npm install @openapitools/openapi-generator-cli -g - # Python client - - openapi-generator generate - -i http://runservice:8080/v3/api-docs - -g python - -o flingclient.py - --enable-post-process-file - # JavaScript client - - openapi-generator generate - -i http://runservice:8080/v3/api-docs - -g javascript - --additional-properties projectName=@fling/flingclient,usePromises=true,npmRepository=https://nexus.friedl.net/repository/npm-private/ - -o flingclient.js - --enable-post-process-file - - cd flingclient.js && npm install && npm run build - - echo "https://nexus.friedl.net/repository/npm-private/" >> .npmrc - - echo -n "_auth=" >> .npmrc && echo -n "$NEXUS_USER:$NEXUS_PASSWORD" | base64 >> .npmrc - - echo "email=dev@friedl.net" >> .npmrc - - npm publish - volumes: - name: m2-cache host: diff --git a/service/fling/src/main/java/net/friedl/fling/FlingConfiguration.java b/service/fling/src/main/java/net/friedl/fling/FlingConfiguration.java index 979d530..485d4e4 100644 --- a/service/fling/src/main/java/net/friedl/fling/FlingConfiguration.java +++ b/service/fling/src/main/java/net/friedl/fling/FlingConfiguration.java @@ -3,7 +3,7 @@ package net.friedl.fling; import java.nio.file.Path; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.crypto.argon2.Argon2PasswordEncoder; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -19,7 +19,7 @@ public class FlingConfiguration { @Bean public PasswordEncoder passwordEncoder() { - return new Argon2PasswordEncoder(); + return new BCryptPasswordEncoder(); } @Bean diff --git a/service/fling/src/main/java/net/friedl/fling/security/FlingWebSecurityConfigurer.java b/service/fling/src/main/java/net/friedl/fling/security/FlingWebSecurityConfigurer.java index 5658bf1..7ff70ad 100644 --- a/service/fling/src/main/java/net/friedl/fling/security/FlingWebSecurityConfigurer.java +++ b/service/fling/src/main/java/net/friedl/fling/security/FlingWebSecurityConfigurer.java @@ -4,9 +4,8 @@ import static net.friedl.fling.security.FlingAuthorities.FLING_ADMIN; import static org.springframework.security.config.Customizer.withDefaults; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -24,12 +23,11 @@ import net.friedl.fling.security.authentication.JwtAuthenticationFilter; import net.friedl.fling.service.AuthorizationService; @Slf4j -@Configuration @EnableWebSecurity +@ConfigurationProperties(prefix = "fling.security") @Getter @Setter public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter { - @Value("fling.security.allowedOrigins") private List allowedOrigins; private JwtAuthenticationFilter jwtAuthenticationFilter; diff --git a/service/fling/src/main/java/net/friedl/fling/security/authentication/JwtAuthenticationFilter.java b/service/fling/src/main/java/net/friedl/fling/security/authentication/JwtAuthenticationFilter.java index 2ad3c5b..b4e5dc4 100644 --- a/service/fling/src/main/java/net/friedl/fling/security/authentication/JwtAuthenticationFilter.java +++ b/service/fling/src/main/java/net/friedl/fling/security/authentication/JwtAuthenticationFilter.java @@ -36,8 +36,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { String header = request.getHeader(HEADER_STRING); if (header == null || !header.startsWith(TOKEN_PREFIX)) { - log.info("Anonymous request for {} {}?{}", request.getMethod(), request.getRequestURL(), - request.getQueryString()); + log.info("Anonymous request for {} {}{}", request.getMethod(), request.getRequestURL(), + request.getQueryString() != null ? "?"+request.getQueryString(): ""); filterChain.doFilter(request, response); return; } @@ -47,8 +47,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { SecurityContext securityContext = SecurityContextHolder.getContext(); if (securityContext.getAuthentication() == null) { - log.info("Authenticating request for {} {}?{}", request.getMethod(), request.getRequestURL(), - request.getQueryString()); + log.info("Authenticating request for {} {}{}", request.getMethod(), request.getRequestURL(), + request.getQueryString() != null ? "?"+request.getQueryString(): ""); FlingToken token = authenticationService.parseAuthentication(authToken); log.info("Authenticated as {}", token.getAuthorities().stream() .map(GrantedAuthority::getAuthority).collect(Collectors.joining(","))); diff --git a/service/fling/src/main/java/net/friedl/fling/service/AuthenticationService.java b/service/fling/src/main/java/net/friedl/fling/service/AuthenticationService.java index afe15f1..71038aa 100644 --- a/service/fling/src/main/java/net/friedl/fling/service/AuthenticationService.java +++ b/service/fling/src/main/java/net/friedl/fling/service/AuthenticationService.java @@ -5,6 +5,7 @@ import java.time.Instant; import java.util.Date; import java.util.Optional; import java.util.UUID; +import javax.persistence.EntityNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.BadCredentialsException; @@ -70,6 +71,8 @@ public class AuthenticationService { public Optional authenticate(UserAuthDto userAuth) { log.info("Authenticating for fling [.shareId={}]", userAuth.getShareId()); FlingEntity flingEntity = flingRepository.findByShareId(userAuth.getShareId()); + if(flingEntity == null) { throw new EntityNotFoundException("No entity for shareId="+userAuth.getShareId()); } + String providedAuthCodeHash = passwordEncoder.encode(userAuth.getAuthCode()); String actualAuthCodeHash = flingEntity.getAuthCode(); diff --git a/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java b/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java index d1a151d..a405cfe 100644 --- a/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java +++ b/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java @@ -1,6 +1,7 @@ package net.friedl.fling.service; import java.util.UUID; +import javax.persistence.EntityNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.stereotype.Service; @@ -69,6 +70,7 @@ public class AuthorizationService { public boolean allowFlingAccessByShareId(String shareId, AbstractAuthenticationToken token) { FlingEntity flingEntity = flingRepository.findByShareId(shareId); + if(flingEntity == null) { throw new EntityNotFoundException("No entity for shareId="+shareId); } return allowFlingAccess(flingEntity.getId(), token); } diff --git a/service/fling/src/main/java/net/friedl/fling/service/FlingService.java b/service/fling/src/main/java/net/friedl/fling/service/FlingService.java index 2bf418c..ecfb474 100644 --- a/service/fling/src/main/java/net/friedl/fling/service/FlingService.java +++ b/service/fling/src/main/java/net/friedl/fling/service/FlingService.java @@ -5,6 +5,7 @@ import java.util.Base64; import java.util.List; import java.util.Set; import java.util.UUID; +import javax.persistence.EntityNotFoundException; import javax.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.keygen.KeyGenerators; @@ -89,6 +90,7 @@ public class FlingService { public FlingDto getByShareId(String shareId) { FlingEntity flingEntity = flingRepository.findByShareId(shareId); + if(flingEntity == null) { throw new EntityNotFoundException("No entity for shareId="+shareId); } return flingMapper.map(flingEntity); } diff --git a/service/fling/src/main/resources/application-local.yml b/service/fling/src/main/resources/application-local.yml index 218b85c..43108ed 100644 --- a/service/fling/src/main/resources/application-local.yml +++ b/service/fling/src/main/resources/application-local.yml @@ -28,8 +28,8 @@ fling: - "http://localhost:3000" - "http://localhost:5000" - "http://10.0.2.2:5000" - admin-name: "adminName" - admin-password: "adminPassword" + admin-name: "admin" + admin-password: "123" signing-key: "changeitchangeitchangeitchangeit" jwt-expiration: "180000" api: diff --git a/service/fling/src/test/java/net/friedl/fling/service/AuthenticationServiceTest.java b/service/fling/src/test/java/net/friedl/fling/service/AuthenticationServiceTest.java index 14181fa..658ef44 100644 --- a/service/fling/src/test/java/net/friedl/fling/service/AuthenticationServiceTest.java +++ b/service/fling/src/test/java/net/friedl/fling/service/AuthenticationServiceTest.java @@ -11,6 +11,7 @@ import java.security.Key; import java.util.Map; import java.util.Optional; import java.util.UUID; +import javax.persistence.EntityNotFoundException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -115,6 +116,18 @@ public class AuthenticationServiceTest { assertThat(authenticationService.authenticate(userAuthDto), not(equalTo(Optional.empty()))); } + @Test + public void authenticate_noFlingForShareId_throws() { + UserAuthDto userAuthDto = UserAuthDto.builder() + .authCode("authCode") + .shareId("doesNotExist").build(); + + when(flingRepository.findByShareId(any(String.class))).thenReturn(null); + when(passwordEncoder.encode(any(String.class))).thenReturn("authCodeHash"); + + assertThrows(EntityNotFoundException.class, () -> authenticationService.authenticate(userAuthDto)); + } + @Test public void parseAuthentication_owner_AdminAuthority() { Jws jwsClaims = new DefaultJws<>(new DefaultJwsHeader(), diff --git a/service/fling/src/test/java/net/friedl/fling/service/AuthorizationServiceTest.java b/service/fling/src/test/java/net/friedl/fling/service/AuthorizationServiceTest.java index 5540941..3ad1820 100644 --- a/service/fling/src/test/java/net/friedl/fling/service/AuthorizationServiceTest.java +++ b/service/fling/src/test/java/net/friedl/fling/service/AuthorizationServiceTest.java @@ -1,10 +1,13 @@ package net.friedl.fling.service; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import java.util.List; import java.util.UUID; +import javax.persistence.EntityNotFoundException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -113,4 +116,14 @@ public class AuthorizationServiceTest { FlingToken flingToken = new FlingToken(new FlingUserAuthority(new UUID(0, 0)), "jwtToken"); assertTrue(authorizationService.allowFlingAccess(new UUID(0, 0), flingToken)); } + + @Test + public void allowFlingAccessByShareId_noFlingForShareId_throw() { + FlingToken flingToken = new FlingToken(new FlingUserAuthority(new UUID(0, 0)), "jwtToken"); + when(flingRepository.findByShareId(any(String.class))).thenReturn(null); + + assertThrows(EntityNotFoundException.class, + () -> authorizationService.allowFlingAccessByShareId("doesNotExist", flingToken)); + } + } diff --git a/service/fling/src/test/java/net/friedl/fling/service/FlingServiceTest.java b/service/fling/src/test/java/net/friedl/fling/service/FlingServiceTest.java index 840285f..f16072b 100644 --- a/service/fling/src/test/java/net/friedl/fling/service/FlingServiceTest.java +++ b/service/fling/src/test/java/net/friedl/fling/service/FlingServiceTest.java @@ -9,6 +9,7 @@ import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -17,6 +18,7 @@ import java.util.List; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import javax.persistence.EntityNotFoundException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -161,6 +163,13 @@ public class FlingServiceTest { assertThat(foundFling.getShareId(), equalTo("shareId2")); } + @Test + public void getByShareId_noFlingForShareId_throws() { + when(flingRepository.findByShareId(any(String.class))).thenReturn(null); + + assertThrows(EntityNotFoundException.class, () -> flingService.getByShareId("doesNotExist")); + } + @Test public void delete_deletesFromArchiveAndDb() throws IOException { UUID testId = UUID.randomUUID(); diff --git a/web/fling/.env b/web/fling/.env index 1ffa947..e605af4 100644 --- a/web/fling/.env +++ b/web/fling/.env @@ -1,2 +1,2 @@ -REACT_APP_API=https://fling.friedl.net/api +REACT_APP_API=https://fling.friedl.net REACT_APP_LOGLEVEL=warn diff --git a/web/fling/.env.development.local b/web/fling/.env.development.local index 445b133..ecf9b5b 100644 --- a/web/fling/.env.development.local +++ b/web/fling/.env.development.local @@ -1,2 +1,2 @@ -REACT_APP_API=http://localhost:8080/api +REACT_APP_API=http://localhost:8080/ REACT_APP_LOGLEVEL=trace diff --git a/web/fling/package-lock.json b/web/fling/package-lock.json index d495c51..c595a82 100644 --- a/web/fling/package-lock.json +++ b/web/fling/package-lock.json @@ -4,6 +4,135 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/cli": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.10.4.tgz", + "integrity": "sha512-xX99K4V1BzGJdQANK5cwK+EpF1vP9gvqhn+iWvG+TubCjecplW7RSQimJ2jcCvu6fnK5pY6mZMdu6EWTj32QVA==", + "requires": { + "chokidar": "^2.1.8", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.13", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "optional": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "optional": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "@babel/code-frame": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", @@ -1078,6 +1207,15 @@ "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==" }, + "@fling/flingclient": { + "version": "0.1.0-snapshot", + "resolved": "https://nexus.friedl.net/repository/npm-private/@fling/flingclient/-/flingclient-0.1.0-snapshot.tgz", + "integrity": "sha512-KXeJE/tTCi+IRBZ8pBeFLFEn7GDBWw/aIDj4xaofjw6S0DFEpw5TwW+Oh45NALk/SEiR4DKBuG/sfgiHrpZwLA==", + "requires": { + "@babel/cli": "^7.0.0", + "superagent": "3.7.0" + } + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", @@ -3808,6 +3946,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", @@ -5838,6 +5981,11 @@ "mime-types": "^2.1.12" } }, + "formidable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==" + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -5907,6 +6055,11 @@ "minipass": "^3.0.0" } }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==" + }, "fs-write-stream-atomic": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", @@ -6154,12 +6307,12 @@ } }, "globule": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", - "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", + "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", "requires": { "glob": "~7.1.1", - "lodash": "~4.17.12", + "lodash": "~4.17.10", "minimatch": "~3.0.2" } }, @@ -6512,9 +6665,9 @@ "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" }, "http-proxy": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -8132,9 +8285,9 @@ } }, "js-base64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", - "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.3.tgz", + "integrity": "sha512-fiUvdfCaAXoQTHdKMgTvg6IkecXDcVz6V5rlftUTclF9IKBjMizvSdQaCl/z/6TApDeby5NL+axYou3i0mu1Pg==" }, "js-tokens": { "version": "4.0.0", @@ -8448,9 +8601,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -9270,9 +9423,9 @@ "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==" }, "node-sass": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.0.tgz", - "integrity": "sha512-AxqU+DFpk0lEz95sI6jO0hU0Rwyw7BXVEv6o9OItoXLyeygPeaSpiV4rwQb10JiTghHaa0gZeD21sz+OsQluaw==", + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", + "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", "requires": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -9288,7 +9441,7 @@ "node-gyp": "^3.8.0", "npmlog": "^4.0.0", "request": "^2.88.0", - "sass-graph": "^2.2.4", + "sass-graph": "2.2.5", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" }, @@ -12229,219 +12382,14 @@ "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==" }, "sass-graph": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", - "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", + "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", "requires": { "glob": "^7.0.0", "lodash": "^4.0.0", "scss-tokenizer": "^0.2.3", - "yargs": "^7.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "^1.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "requires": { - "lcid": "^1.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "^0.2.0" - } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - } - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - }, - "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "requires": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.0" - } - }, - "yargs-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", - "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "requires": { - "camelcase": "^3.0.0" - } - } + "yargs": "^13.3.2" } }, "sass-loader": { @@ -13480,6 +13428,60 @@ } } }, + "superagent": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.7.0.tgz", + "integrity": "sha512-/8trxO6NbLx4YXb7IeeFTSmsQ35pQBiTBsLNvobZx7qBzBeHYvKCyIIhW2gNcWbLzYxPAjdgFbiepd8ypwC0Gw==", + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.1.1", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/web/fling/package.json b/web/fling/package.json index 20e6ba4..1d53417 100644 --- a/web/fling/package.json +++ b/web/fling/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@fling/flingclient": "0.1.0-snapshot", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", @@ -11,7 +12,7 @@ "core-js": "^3.6.5", "jwt-decode": "^2.2.0", "loglevel": "^1.6.8", - "node-sass": "^4.14.0", + "node-sass": "^4.14.1", "normalize.css": "^8.0.1", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/web/fling/src/components/admin/Login.jsx b/web/fling/src/components/admin/Login.jsx index 361dc46..b56f599 100644 --- a/web/fling/src/components/admin/Login.jsx +++ b/web/fling/src/components/admin/Login.jsx @@ -1,88 +1,59 @@ import log from 'loglevel'; -import React, {useState, useEffect} from 'react'; +import React, {useState} from 'react'; import {useHistory, useLocation} from 'react-router-dom'; -import request, {setAuth} from '../../util/request'; - -import Error from './Error'; +import {fc, AuthClient} from '../../util/fc'; export default function Login() { - const [errors, setErrors] = useState([]); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const history = useHistory(); - const location = useLocation(); - const { from } = location.state || { from: { pathname: "/admin" } }; + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const history = useHistory(); + const location = useLocation(); + const { from } = location.state || { from: { pathname: "/admin" } }; - useEffect(() => setAuth(null), []); - - return ( -
-
- -
-
- - -
-
- - -
-
-
- -
- -
- -
- -

Ready. Set. Fling.

+ return ( +
+
+
+
+ + setUsername(ev.currentTarget.value)} />
+
+ + setPassword(ev.currentTarget.value)} /> +
+
+
+ +
+ +
+ -
- ); +

Ready. Set. Fling.

+
- function handleSubmit(ev) { - ev.preventDefault(); +
+ ); - request.post("/auth/owner", {'username': username, 'password': password}) - .then(response => { - log.info("Logged in successfully"); - setAuth(response.data); - history.replace(from); - }) - .catch(error => { - log.error(error); - let response = error.response; - response.data && response.data.message && setErrors( prev => [response.data.message, ...prev] ); - }); - }; + function handleSubmit(ev) { + ev.preventDefault(); - function handleChange(ev) { - let name = ev.target.name; - let val = ev.target.value; + let authClient = new AuthClient(); + let opt = {adminAuth: new fc.AdminAuth(username, password)}; - switch(name) { - case "username": - setUsername(val); - break; - case "password": - setPassword(val); - break; - default: - log.error(`Cannot handle change ${name}`); - break; - } - }; - - function clearErrors() { - setErrors([]); - } + authClient.authenticateOwner(opt) + .then(response => { + log.info("Login successful"); + sessionStorage.setItem['token'] = response; + log.info("Returning back to", from); + history.replace(from); + }).catch(log.error); + }; } diff --git a/web/fling/src/util/fc.js b/web/fling/src/util/fc.js new file mode 100644 index 0000000..b901f7a --- /dev/null +++ b/web/fling/src/util/fc.js @@ -0,0 +1,25 @@ +import * as fc from '@fling/flingclient'; + +let clientConfig = (token) => { + let config = new fc.ApiClient(); + config.basePath = process.env.REACT_APP_API.replace(/\/+$/, ''); + + token = token || sessionStorage.getItem['token']; + if(token) { config.authentications['bearer'].accessToken = token; } + + return config; +}; + +function FlingClient(token) { + return new fc.FlingApi(clientConfig(token)); +} + +function ArtifactClient(token) { + return new fc.ArtifactApi(clientConfig(token)); +} + +function AuthClient() { + return new fc.AuthApi(clientConfig()); +} + +export {FlingClient, ArtifactClient, AuthClient, fc};