Use generated client in web interface
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
8e0685819d
commit
39fd416b4a
17 changed files with 385 additions and 346 deletions
60
.drone.yml
60
.drone.yml
|
@ -26,6 +26,36 @@ steps:
|
||||||
- java -jar fling-0.1.0-SNAPSHOT.jar
|
- java -jar fling-0.1.0-SNAPSHOT.jar
|
||||||
detach: true
|
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
|
- name: build-web
|
||||||
image: node:latest
|
image: node:latest
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -60,36 +90,6 @@ steps:
|
||||||
build_args:
|
build_args:
|
||||||
- VERSION=0.1.0-snapshot
|
- 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:
|
volumes:
|
||||||
- name: m2-cache
|
- name: m2-cache
|
||||||
host:
|
host:
|
||||||
|
|
|
@ -3,7 +3,7 @@ package net.friedl.fling;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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 org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
@ -19,7 +19,7 @@ public class FlingConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PasswordEncoder passwordEncoder() {
|
public PasswordEncoder passwordEncoder() {
|
||||||
return new Argon2PasswordEncoder();
|
return new BCryptPasswordEncoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -4,9 +4,8 @@ import static net.friedl.fling.security.FlingAuthorities.FLING_ADMIN;
|
||||||
import static org.springframework.security.config.Customizer.withDefaults;
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
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;
|
import net.friedl.fling.service.AuthorizationService;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@ConfigurationProperties(prefix = "fling.security")
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
|
public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
|
||||||
@Value("fling.security.allowedOrigins")
|
|
||||||
private List<String> allowedOrigins;
|
private List<String> allowedOrigins;
|
||||||
|
|
||||||
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||||
|
|
|
@ -36,8 +36,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
String header = request.getHeader(HEADER_STRING);
|
String header = request.getHeader(HEADER_STRING);
|
||||||
|
|
||||||
if (header == null || !header.startsWith(TOKEN_PREFIX)) {
|
if (header == null || !header.startsWith(TOKEN_PREFIX)) {
|
||||||
log.info("Anonymous request for {} {}?{}", request.getMethod(), request.getRequestURL(),
|
log.info("Anonymous request for {} {}{}", request.getMethod(), request.getRequestURL(),
|
||||||
request.getQueryString());
|
request.getQueryString() != null ? "?"+request.getQueryString(): "");
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||||
|
|
||||||
if (securityContext.getAuthentication() == null) {
|
if (securityContext.getAuthentication() == null) {
|
||||||
log.info("Authenticating request for {} {}?{}", request.getMethod(), request.getRequestURL(),
|
log.info("Authenticating request for {} {}{}", request.getMethod(), request.getRequestURL(),
|
||||||
request.getQueryString());
|
request.getQueryString() != null ? "?"+request.getQueryString(): "");
|
||||||
FlingToken token = authenticationService.parseAuthentication(authToken);
|
FlingToken token = authenticationService.parseAuthentication(authToken);
|
||||||
log.info("Authenticated as {}", token.getAuthorities().stream()
|
log.info("Authenticated as {}", token.getAuthorities().stream()
|
||||||
.map(GrantedAuthority::getAuthority).collect(Collectors.joining(",")));
|
.map(GrantedAuthority::getAuthority).collect(Collectors.joining(",")));
|
||||||
|
|
|
@ -5,6 +5,7 @@ import java.time.Instant;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.persistence.EntityNotFoundException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
@ -70,6 +71,8 @@ public class AuthenticationService {
|
||||||
public Optional<String> authenticate(UserAuthDto userAuth) {
|
public Optional<String> authenticate(UserAuthDto userAuth) {
|
||||||
log.info("Authenticating for fling [.shareId={}]", userAuth.getShareId());
|
log.info("Authenticating for fling [.shareId={}]", userAuth.getShareId());
|
||||||
FlingEntity flingEntity = flingRepository.findByShareId(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 providedAuthCodeHash = passwordEncoder.encode(userAuth.getAuthCode());
|
||||||
String actualAuthCodeHash = flingEntity.getAuthCode();
|
String actualAuthCodeHash = flingEntity.getAuthCode();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.friedl.fling.service;
|
package net.friedl.fling.service;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.persistence.EntityNotFoundException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -69,6 +70,7 @@ public class AuthorizationService {
|
||||||
|
|
||||||
public boolean allowFlingAccessByShareId(String shareId, AbstractAuthenticationToken token) {
|
public boolean allowFlingAccessByShareId(String shareId, AbstractAuthenticationToken token) {
|
||||||
FlingEntity flingEntity = flingRepository.findByShareId(shareId);
|
FlingEntity flingEntity = flingRepository.findByShareId(shareId);
|
||||||
|
if(flingEntity == null) { throw new EntityNotFoundException("No entity for shareId="+shareId); }
|
||||||
return allowFlingAccess(flingEntity.getId(), token);
|
return allowFlingAccess(flingEntity.getId(), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.persistence.EntityNotFoundException;
|
||||||
import javax.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.crypto.keygen.KeyGenerators;
|
import org.springframework.security.crypto.keygen.KeyGenerators;
|
||||||
|
@ -89,6 +90,7 @@ public class FlingService {
|
||||||
|
|
||||||
public FlingDto getByShareId(String shareId) {
|
public FlingDto getByShareId(String shareId) {
|
||||||
FlingEntity flingEntity = flingRepository.findByShareId(shareId);
|
FlingEntity flingEntity = flingRepository.findByShareId(shareId);
|
||||||
|
if(flingEntity == null) { throw new EntityNotFoundException("No entity for shareId="+shareId); }
|
||||||
return flingMapper.map(flingEntity);
|
return flingMapper.map(flingEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,8 @@ fling:
|
||||||
- "http://localhost:3000"
|
- "http://localhost:3000"
|
||||||
- "http://localhost:5000"
|
- "http://localhost:5000"
|
||||||
- "http://10.0.2.2:5000"
|
- "http://10.0.2.2:5000"
|
||||||
admin-name: "adminName"
|
admin-name: "admin"
|
||||||
admin-password: "adminPassword"
|
admin-password: "123"
|
||||||
signing-key: "changeitchangeitchangeitchangeit"
|
signing-key: "changeitchangeitchangeitchangeit"
|
||||||
jwt-expiration: "180000"
|
jwt-expiration: "180000"
|
||||||
api:
|
api:
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.security.Key;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.persistence.EntityNotFoundException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -115,6 +116,18 @@ public class AuthenticationServiceTest {
|
||||||
assertThat(authenticationService.authenticate(userAuthDto), not(equalTo(Optional.empty())));
|
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
|
@Test
|
||||||
public void parseAuthentication_owner_AdminAuthority() {
|
public void parseAuthentication_owner_AdminAuthority() {
|
||||||
Jws<Claims> jwsClaims = new DefaultJws<>(new DefaultJwsHeader(),
|
Jws<Claims> jwsClaims = new DefaultJws<>(new DefaultJwsHeader(),
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package net.friedl.fling.service;
|
package net.friedl.fling.service;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
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.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.persistence.EntityNotFoundException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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");
|
FlingToken flingToken = new FlingToken(new FlingUserAuthority(new UUID(0, 0)), "jwtToken");
|
||||||
assertTrue(authorizationService.allowFlingAccess(new UUID(0, 0), flingToken));
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.emptyOrNullString;
|
import static org.hamcrest.Matchers.emptyOrNullString;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -17,6 +18,7 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import javax.persistence.EntityNotFoundException;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
@ -161,6 +163,13 @@ public class FlingServiceTest {
|
||||||
assertThat(foundFling.getShareId(), equalTo("shareId2"));
|
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
|
@Test
|
||||||
public void delete_deletesFromArchiveAndDb() throws IOException {
|
public void delete_deletesFromArchiveAndDb() throws IOException {
|
||||||
UUID testId = UUID.randomUUID();
|
UUID testId = UUID.randomUUID();
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
REACT_APP_API=https://fling.friedl.net/api
|
REACT_APP_API=https://fling.friedl.net
|
||||||
REACT_APP_LOGLEVEL=warn
|
REACT_APP_LOGLEVEL=warn
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
REACT_APP_API=http://localhost:8080/api
|
REACT_APP_API=http://localhost:8080/
|
||||||
REACT_APP_LOGLEVEL=trace
|
REACT_APP_LOGLEVEL=trace
|
||||||
|
|
454
web/fling/package-lock.json
generated
454
web/fling/package-lock.json
generated
|
@ -4,6 +4,135 @@
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"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": {
|
"@babel/code-frame": {
|
||||||
"version": "7.8.3",
|
"version": "7.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
|
||||||
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
|
"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": {
|
"@hapi/address": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
"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": {
|
"copy-concurrently": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
|
||||||
|
@ -5838,6 +5981,11 @@
|
||||||
"mime-types": "^2.1.12"
|
"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": {
|
"forwarded": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||||
|
@ -5907,6 +6055,11 @@
|
||||||
"minipass": "^3.0.0"
|
"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": {
|
"fs-write-stream-atomic": {
|
||||||
"version": "1.0.10",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
|
||||||
|
@ -6154,12 +6307,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"globule": {
|
"globule": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
|
||||||
"integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==",
|
"integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "~7.1.1",
|
"glob": "~7.1.1",
|
||||||
"lodash": "~4.17.12",
|
"lodash": "~4.17.10",
|
||||||
"minimatch": "~3.0.2"
|
"minimatch": "~3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -6512,9 +6665,9 @@
|
||||||
"integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q="
|
"integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q="
|
||||||
},
|
},
|
||||||
"http-proxy": {
|
"http-proxy": {
|
||||||
"version": "1.18.0",
|
"version": "1.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||||
"integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==",
|
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"eventemitter3": "^4.0.0",
|
"eventemitter3": "^4.0.0",
|
||||||
"follow-redirects": "^1.0.0",
|
"follow-redirects": "^1.0.0",
|
||||||
|
@ -8132,9 +8285,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"js-base64": {
|
"js-base64": {
|
||||||
"version": "2.5.2",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.3.tgz",
|
||||||
"integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ=="
|
"integrity": "sha512-fiUvdfCaAXoQTHdKMgTvg6IkecXDcVz6V5rlftUTclF9IKBjMizvSdQaCl/z/6TApDeby5NL+axYou3i0mu1Pg=="
|
||||||
},
|
},
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
@ -8448,9 +8601,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.15",
|
"version": "4.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
|
||||||
},
|
},
|
||||||
"lodash._reinterpolate": {
|
"lodash._reinterpolate": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
|
@ -9270,9 +9423,9 @@
|
||||||
"integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ=="
|
"integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ=="
|
||||||
},
|
},
|
||||||
"node-sass": {
|
"node-sass": {
|
||||||
"version": "4.14.0",
|
"version": "4.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz",
|
||||||
"integrity": "sha512-AxqU+DFpk0lEz95sI6jO0hU0Rwyw7BXVEv6o9OItoXLyeygPeaSpiV4rwQb10JiTghHaa0gZeD21sz+OsQluaw==",
|
"integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async-foreach": "^0.1.3",
|
"async-foreach": "^0.1.3",
|
||||||
"chalk": "^1.1.1",
|
"chalk": "^1.1.1",
|
||||||
|
@ -9288,7 +9441,7 @@
|
||||||
"node-gyp": "^3.8.0",
|
"node-gyp": "^3.8.0",
|
||||||
"npmlog": "^4.0.0",
|
"npmlog": "^4.0.0",
|
||||||
"request": "^2.88.0",
|
"request": "^2.88.0",
|
||||||
"sass-graph": "^2.2.4",
|
"sass-graph": "2.2.5",
|
||||||
"stdout-stream": "^1.4.0",
|
"stdout-stream": "^1.4.0",
|
||||||
"true-case-path": "^1.0.2"
|
"true-case-path": "^1.0.2"
|
||||||
},
|
},
|
||||||
|
@ -12229,219 +12382,14 @@
|
||||||
"integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg=="
|
"integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg=="
|
||||||
},
|
},
|
||||||
"sass-graph": {
|
"sass-graph": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz",
|
||||||
"integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
|
"integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob": "^7.0.0",
|
"glob": "^7.0.0",
|
||||||
"lodash": "^4.0.0",
|
"lodash": "^4.0.0",
|
||||||
"scss-tokenizer": "^0.2.3",
|
"scss-tokenizer": "^0.2.3",
|
||||||
"yargs": "^7.0.0"
|
"yargs": "^13.3.2"
|
||||||
},
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sass-loader": {
|
"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": {
|
"supports-color": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fling/flingclient": "0.1.0-snapshot",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.5.0",
|
"@testing-library/react": "^9.5.0",
|
||||||
"@testing-library/user-event": "^7.2.1",
|
"@testing-library/user-event": "^7.2.1",
|
||||||
|
@ -11,7 +12,7 @@
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"jwt-decode": "^2.2.0",
|
"jwt-decode": "^2.2.0",
|
||||||
"loglevel": "^1.6.8",
|
"loglevel": "^1.6.8",
|
||||||
"node-sass": "^4.14.0",
|
"node-sass": "^4.14.1",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
|
|
|
@ -1,88 +1,59 @@
|
||||||
import log from 'loglevel';
|
import log from 'loglevel';
|
||||||
import React, {useState, useEffect} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {useHistory, useLocation} from 'react-router-dom';
|
import {useHistory, useLocation} from 'react-router-dom';
|
||||||
|
|
||||||
import request, {setAuth} from '../../util/request';
|
import {fc, AuthClient} from '../../util/fc';
|
||||||
|
|
||||||
import Error from './Error';
|
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const [errors, setErrors] = useState([]);
|
const [username, setUsername] = useState("");
|
||||||
const [username, setUsername] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const history = useHistory();
|
||||||
const history = useHistory();
|
const location = useLocation();
|
||||||
const location = useLocation();
|
const { from } = location.state || { from: { pathname: "/admin" } };
|
||||||
const { from } = location.state || { from: { pathname: "/admin" } };
|
|
||||||
|
|
||||||
useEffect(() => setAuth(null), []);
|
return (
|
||||||
|
<div className="container-center">
|
||||||
return (
|
<div>
|
||||||
<div className="container-center">
|
<form className="login-form" onSubmit={handleSubmit}>
|
||||||
<div>
|
<div className="form-group">
|
||||||
<Error errors={errors} clearErrors={clearErrors} >
|
<label className="form-label" htmlFor="username">Username</label>
|
||||||
<form className="login-form" onSubmit={handleSubmit}>
|
<input className="form-input" id="username" name="username" type="text" placeholder="Username"
|
||||||
<div className="form-group">
|
value={username} onChange={ev => setUsername(ev.currentTarget.value)} />
|
||||||
<label className="form-label" htmlFor="username">Username</label>
|
|
||||||
<input className="form-input" id="username" name="username" type="text" placeholder="Username"
|
|
||||||
value={username} onChange={handleChange} />
|
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
<label className="form-label" htmlFor="password">Password</label>
|
|
||||||
<input className="form-input" id="password" name="password" type="password" placeholder={"*".repeat(18)}
|
|
||||||
value={password} onChange={handleChange} />
|
|
||||||
</div>
|
|
||||||
<div className="login-action-row">
|
|
||||||
<div className="form-group">
|
|
||||||
<label className="form-switch input-sm">
|
|
||||||
<input type="checkbox" />
|
|
||||||
<i className="form-icon" /> Remember me
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<button className="btn btn-primary" type="submit">Sign In</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</Error>
|
|
||||||
|
|
||||||
<p className="login-footer">Ready. Set. Fling.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label className="form-label" htmlFor="password">Password</label>
|
||||||
|
<input className="form-input" id="password" name="password" type="password" placeholder={"*".repeat(18)}
|
||||||
|
value={password} onChange={ev => setPassword(ev.currentTarget.value)} />
|
||||||
|
</div>
|
||||||
|
<div className="login-action-row">
|
||||||
|
<div className="form-group">
|
||||||
|
<label className="form-switch input-sm">
|
||||||
|
<input type="checkbox" />
|
||||||
|
<i className="form-icon" /> Remember me
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button className="btn btn-primary" type="submit">Sign In</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
<p className="login-footer">Ready. Set. Fling.</p>
|
||||||
);
|
</div>
|
||||||
|
|
||||||
function handleSubmit(ev) {
|
</div>
|
||||||
ev.preventDefault();
|
);
|
||||||
|
|
||||||
request.post("/auth/owner", {'username': username, 'password': password})
|
function handleSubmit(ev) {
|
||||||
.then(response => {
|
ev.preventDefault();
|
||||||
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 handleChange(ev) {
|
let authClient = new AuthClient();
|
||||||
let name = ev.target.name;
|
let opt = {adminAuth: new fc.AdminAuth(username, password)};
|
||||||
let val = ev.target.value;
|
|
||||||
|
|
||||||
switch(name) {
|
authClient.authenticateOwner(opt)
|
||||||
case "username":
|
.then(response => {
|
||||||
setUsername(val);
|
log.info("Login successful");
|
||||||
break;
|
sessionStorage.setItem['token'] = response;
|
||||||
case "password":
|
log.info("Returning back to", from);
|
||||||
setPassword(val);
|
history.replace(from);
|
||||||
break;
|
}).catch(log.error);
|
||||||
default:
|
};
|
||||||
log.error(`Cannot handle change ${name}`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function clearErrors() {
|
|
||||||
setErrors([]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
25
web/fling/src/util/fc.js
Normal file
25
web/fling/src/util/fc.js
Normal file
|
@ -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};
|
Loading…
Reference in a new issue