diff --git a/.gitignore b/.gitignore index 050e01025..76178c9b0 100644 --- a/.gitignore +++ b/.gitignore @@ -394,4 +394,9 @@ rinteg #Local run with durable H2 shell script wrapper **/application-h2durable.properties -rdurable \ No newline at end of file +rdurable + +#Local build with no tests script wrapper +build-no-tests + +beacon/spring/out diff --git a/backend/build.gradle b/backend/build.gradle index fb7c995d1..59bb93bc1 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -1,9 +1,9 @@ plugins { id 'groovy' id 'war' - id 'org.springframework.boot' version '2.0.0.RELEASE' + id 'org.springframework.boot' version '2.4.2' id 'com.gorylenko.gradle-git-properties' version '1.4.21' - id 'io.franzbecker.gradle-lombok' version '1.13' + id 'io.freefair.lombok' version '5.3.0' id 'com.palantir.docker' version '0.20.1' id 'com.palantir.docker-run' version '0.20.1' } @@ -11,8 +11,8 @@ plugins { apply plugin: 'io.spring.dependency-management' apply plugin: 'jacoco' -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = 11 +targetCompatibility = 11 repositories { jcenter() @@ -55,13 +55,19 @@ sourceSets { java { srcDirs = [] } + resources { + srcDir new File(buildDir, 'generated/ui') + } } integrationTest { groovy { srcDirs = ['src/integration/groovy'] + compileClasspath += main.output + runtimeClasspath += main.output } resources { srcDir 'src/integration/resources' + srcDir new File(buildDir, 'generated/ui') } } @@ -103,11 +109,7 @@ springBoot { buildInfo() } -lombok { - version = "1.18.4" - //TODO: get new sha256 - sha256 = "" -} +generateLombokConfig.enabled = false dependencies { // opensaml deps @@ -126,7 +128,7 @@ dependencies { } // spring boot auto-config starters - ['starter-web', 'starter-data-jpa', 'starter-security', 'starter-actuator', 'devtools', 'starter-webflux', 'starter-thymeleaf', 'starter-mail'].each { + ['starter-web', 'starter-data-jpa', 'starter-security', 'starter-actuator', 'devtools', 'starter-webflux', 'starter-thymeleaf', 'starter-mail', 'starter-validation'].each { compile "org.springframework.boot:spring-boot-${it}" } // TODO: figure out what this should really be @@ -146,10 +148,12 @@ dependencies { //For easy data mocking capabilities compile 'net.andreinc.mockneat:mockneat:0.1.4' - compile 'org.codehaus.groovy:groovy-all:2.4.15' + compile 'org.codehaus.groovy:groovy-all:3.0.7' //So it works on Java 9 without explicitly requiring to load that module (needed by Hibernate) runtimeOnly 'javax.xml.bind:jaxb-api:2.3.0' + // runtime libraries for later java versions + runtimeOnly 'org.glassfish.jaxb:jaxb-runtime:2.3.0' compile "com.h2database:h2" runtimeOnly "org.postgresql:postgresql" @@ -162,8 +166,8 @@ dependencies { testCompile "org.springframework.boot:spring-boot-starter-test" testCompile "org.springframework.security:spring-security-test" - testCompile "org.spockframework:spock-core:1.1-groovy-2.4" - testCompile "org.spockframework:spock-spring:1.1-groovy-2.4" + testCompile "org.spockframework:spock-core:1.3-groovy-2.5" + testCompile "org.spockframework:spock-spring:1.3-groovy-2.5" testCompile "org.xmlunit:xmlunit-core:2.5.1" testRuntime 'cglib:cglib-nodep:3.2.5' @@ -183,8 +187,8 @@ dependencies { integrationTestCompile 'jp.vmi:selenese-runner-java:3.20.0' integrationTestCompile "org.springframework.boot:spring-boot-starter-test" integrationTestCompile "org.springframework.security:spring-security-test" - integrationTestCompile "org.spockframework:spock-core:1.1-groovy-2.4" - integrationTestCompile "org.spockframework:spock-spring:1.1-groovy-2.4" + integrationTestCompile "org.spockframework:spock-core:1.3-groovy-2.5" + integrationTestCompile "org.spockframework:spock-spring:1.3-groovy-2.5" // CSV file support compile 'com.opencsv:opencsv:4.4' @@ -209,31 +213,6 @@ dependencies { enversTestRuntime configurations.testRuntime } -sourceSets { - main { - groovy { - srcDirs = ['src/main/groovy', 'src/main/java', generatedSrcDir] - } - java { - srcDirs = [] - } - resources { - srcDir new File(buildDir, 'generated/ui') - } - } - integrationTest { - groovy { - srcDirs = ['src/integration/groovy'] - compileClasspath += main.output - runtimeClasspath += main.output - } - resources { - srcDir 'src/integration/resources' - srcDir new File(buildDir, 'generated/ui') - } - } -} - task copyUI(type: Copy) { from tasks.findByPath(':ui:npm_run_buildProd').outputs into new File(buildDir, 'generated/ui/static') @@ -339,7 +318,7 @@ compileJava { } jacoco { - toolVersion = '0.8.1' + toolVersion = '0.8.4' } jacocoTestReport { diff --git a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerVersionEndpointsIntegrationTests.groovy b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerVersionEndpointsIntegrationTests.groovy index 82b143c00..a8d5a68ab 100644 --- a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerVersionEndpointsIntegrationTests.groovy +++ b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerVersionEndpointsIntegrationTests.groovy @@ -125,7 +125,6 @@ class EntityDescriptorControllerVersionEndpointsIntegrationTests extends Specifi }) entityDescriptorRepository.save(it) } - when: def headers = new HttpHeaders().with { it.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) @@ -133,7 +132,7 @@ class EntityDescriptorControllerVersionEndpointsIntegrationTests extends Specifi } def allVersions = getAllEntityDescriptorVersions(ed.resourceId, List) - def edv1 = getEntityDescriptorForVersion(ed.resourceId, allVersions.body[0].id, String).body + String edv1 = getEntityDescriptorForVersion(ed.resourceId, allVersions.body[0].id, String).body def tedv2 = getEntityDescriptorForVersion(ed.resourceId, allVersions.body[1].id, EntityDescriptorRepresentation).body def aedv1 = new JsonSlurper().parseText(edv1).with { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/SearchConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/SearchConfiguration.java index bcd13d547..3678954c3 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/SearchConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/SearchConfiguration.java @@ -6,6 +6,7 @@ import org.apache.lucene.analysis.LowerCaseFilter; import org.apache.lucene.analysis.StopFilter; import org.apache.lucene.analysis.TokenFilter; +import org.apache.lucene.analysis.en.EnglishAnalyzer; import org.apache.lucene.analysis.ngram.NGramTokenFilter; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.analysis.standard.StandardTokenizer; @@ -33,9 +34,9 @@ protected TokenStreamComponents createComponents(String fieldName) { final StandardTokenizer src = new StandardTokenizer(); src.setMaxTokenLength(255); TokenFilter tokenFilter; - tokenFilter = new NGramTokenFilter(src, 3, 10); + tokenFilter = new NGramTokenFilter(src, 3, 10, true); tokenFilter = new LowerCaseFilter(tokenFilter); - tokenFilter = new StopFilter(tokenFilter, StandardAnalyzer.STOP_WORDS_SET); + tokenFilter = new StopFilter(tokenFilter, EnglishAnalyzer.ENGLISH_STOP_WORDS_SET); return new TokenStreamComponents(src, tokenFilter); } }; @@ -50,7 +51,7 @@ protected TokenStreamComponents createComponents(String fieldName) { src.setMaxTokenLength(255); TokenFilter tokenFilter; tokenFilter = new LowerCaseFilter(src); - tokenFilter = new StopFilter(tokenFilter, StandardAnalyzer.STOP_WORDS_SET); + tokenFilter = new StopFilter(tokenFilter, EnglishAnalyzer.ENGLISH_STOP_WORDS_SET); return new TokenStreamComponents(src, tokenFilter); } }; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java index b24cad7c2..cc6847621 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/auto/WebSecurityConfig.java @@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @@ -22,6 +21,7 @@ import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.firewall.DefaultHttpFirewall; import org.springframework.security.web.firewall.HttpFirewall; import org.springframework.security.web.firewall.StrictHttpFirewall; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @@ -34,7 +34,6 @@ * Workaround for slashes in URL from [https://stackoverflow.com/questions/48453980/spring-5-0-3-requestrejectedexception-the-request-was-rejected-because-the-url] */ @Configuration -@AutoConfigureBefore(SpringBootWebSecurityConfiguration.class) @ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class) public class WebSecurityConfig { @@ -57,6 +56,11 @@ public HttpFirewall allowUrlEncodedSlashHttpFirewall() { return firewall; } + @Bean + public HttpFirewall defaultFirewall() { + return new DefaultHttpFirewall(); + } + @Bean @Profile("!no-auth") public WebSecurityConfigurerAdapter defaultAuth() { @@ -144,7 +148,8 @@ protected void configure(HttpSecurity http) throws Exception { @Override public void configure(WebSecurity web) throws Exception { super.configure(web); - web.httpFirewall(allowUrlEncodedSlashHttpFirewall()); + //Switch to the default firewall + web.httpFirewall(defaultFirewall()); } }; } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java index 6c05fa987..5e099f3e6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/FileCheckingFileWritingService.java @@ -63,11 +63,11 @@ private boolean checkContentMatches(InputStream inputStream, String content) thr return Arrays.equals(fileDigest, contentDigest); } - void writeContent(Path path, String content) throws IOException { + protected void writeContent(Path path, String content) throws IOException { Files.write(path, content.getBytes()); } - void writeContent(WritableResource resource, String content) throws IOException { + protected void writeContent(WritableResource resource, String content) throws IOException { try (OutputStream os = resource.getOutputStream()) { os.write(content.getBytes()); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/FilterTargetRepresentationDeserializer.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/FilterTargetRepresentationDeserializer.java index 5d52d2fe5..6ee01690b 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/FilterTargetRepresentationDeserializer.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/FilterTargetRepresentationDeserializer.java @@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterTargetRepresentation; -import jdk.nashorn.internal.runtime.regexp.joni.ast.StringNode; import java.io.IOException; import java.util.ArrayList; diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index d5801c722..de3f94759 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -8,6 +8,8 @@ logging.level.org.springframework=INFO logging.level.edu.internet2.tier.shibboleth.admin.ui=INFO +spring.main.allow-bean-definition-overriding=true + # Database Credentials spring.datasource.username=shibui spring.datasource.password=shibui @@ -34,7 +36,6 @@ spring.jackson.default-property-inclusion=NON_NULL # Liquibase properties spring.liquibase.enabled=false -#spring.liquibase.change-log=classpath:edu/internet2/tier/shibboleth/admin/ui/database/masterchangelog.xml # Hibernate properties # for production never ever use create, create-drop. It's BEST to use validate @@ -48,6 +49,9 @@ spring.jpa.hibernate.use-new-id-generator-mappings=true #Envers versioning spring.jpa.properties.org.hibernate.envers.store_data_at_delete=true +#Needed in the latest versions of Spring Boot when doing manual transaction management like we do in envers versioning code +spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext + # Set the following property to periodically write out the generated metadata files. There is no default value; the following is just an example # shibui.metadata-dir=/opt/shibboleth-idp/metadata/generated shibui.logout-url=/dashboard @@ -93,4 +97,4 @@ shibui.roles=ROLE_ADMIN,ROLE_USER,ROLE_NONE #This property must be set to true in order to enable posting stats to beacon endpoint. Furthermore, appropriate #environment variables must be set for beacon publisher to be used (the ones that are set when running shib-ui in #docker container -shibui.beacon-enabled=true \ No newline at end of file +shibui.beacon-enabled=true diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy index d8d9e7afb..cbe48c847 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy @@ -17,6 +17,7 @@ import org.springframework.core.io.ClassPathResource import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.reactive.server.WebTestClient import org.springframework.test.web.servlet.result.MockMvcResultHandlers +import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.util.DefaultUriBuilderFactory import org.xmlunit.builder.DiffBuilder import org.xmlunit.builder.Input @@ -34,10 +35,11 @@ class EntitiesControllerIntegrationTests extends Specification { @Autowired private WebTestClient webClient - def setup() { + /*def setup() { // yeah, don't ask... this is just shenanigans + // The API is changed. Doesn't work anymore. Not sure if we need it here this.webClient.webClient.uriBuilderFactory.encodingMode = DefaultUriBuilderFactory.EncodingMode.NONE - } + }*/ def "GET /api/entities returns the proper json"() { given: diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerTests.groovy index 30117bc14..ea265d46d 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerTests.groovy @@ -104,7 +104,7 @@ class EntitiesControllerTests extends Specification { then: def x = content() result.andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(expectedBody, false)) } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy index bf3778fbb..ed721055a 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy @@ -102,7 +102,7 @@ class EntityDescriptorControllerTests extends Specification { userRepository.findByUsername(username) >> TestHelpers.generateOptionalUser(username, role) def emptyRecordsFromRepository = [].stream() def expectedEmptyListResponseBody = '[]' - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedHttpResponseStatus = status().isOk() when: @@ -153,7 +153,7 @@ class EntityDescriptorControllerTests extends Specification { ] """ - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedHttpResponseStatus = status().isOk() when: @@ -229,7 +229,7 @@ class EntityDescriptorControllerTests extends Specification { ] """ - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedHttpResponseStatus = status().isOk() when: @@ -282,7 +282,7 @@ class EntityDescriptorControllerTests extends Specification { ] """ - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedHttpResponseStatus = status().isOk() when: @@ -361,7 +361,7 @@ class EntityDescriptorControllerTests extends Specification { when: def result = mockMvc.perform( post('/api/EntityDescriptor') - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: @@ -413,7 +413,7 @@ class EntityDescriptorControllerTests extends Specification { when: def result = mockMvc.perform( post('/api/EntityDescriptor') - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: @@ -449,7 +449,7 @@ class EntityDescriptorControllerTests extends Specification { when: def result = mockMvc.perform( post('/api/EntityDescriptor') - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: @@ -933,7 +933,7 @@ class EntityDescriptorControllerTests extends Specification { when: def result = mockMvc.perform( put("/api/EntityDescriptor/$resourceId") - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: @@ -966,7 +966,7 @@ class EntityDescriptorControllerTests extends Specification { when: def result = mockMvc.perform( put("/api/EntityDescriptor/$resourceId") - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: @@ -992,7 +992,7 @@ class EntityDescriptorControllerTests extends Specification { when: def result = mockMvc.perform( put("/api/EntityDescriptor/$resourceId") - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: @@ -1018,7 +1018,7 @@ class EntityDescriptorControllerTests extends Specification { when: def result = mockMvc.perform( put("/api/EntityDescriptor/$resourceId") - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchControllerTests.groovy index 77ea5ddd0..f452c769a 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchControllerTests.groovy @@ -6,7 +6,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders import spock.lang.Specification import spock.lang.Subject -import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8 +import static org.springframework.http.MediaType.APPLICATION_JSON import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status @@ -36,7 +36,7 @@ class EntityIdsSearchControllerTests extends Specification { def limitValue = "5" def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation(["http://unicon.instructure.com/saml2", "https://idp.unicon.net/idp/shibboleth"]) def expectedHttpResponseStatus = status().isOk() - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedResponseBody = """ { "entityIds":[ @@ -66,7 +66,7 @@ class EntityIdsSearchControllerTests extends Specification { def limitValue = "1" def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation(["http://unicon.instructure.com/saml2"]) def expectedHttpResponseStatus = status().isOk() - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedResponseBody = """ { "entityIds":[ @@ -104,7 +104,7 @@ class EntityIdsSearchControllerTests extends Specification { "https://shibbox.lpplus.net/shibboleth", "https://shibsp.amherst.edu/shibboleth"]) def expectedHttpResponseStatus = status().isOk() - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedResponseBody = """ { "entityIds":[ @@ -141,7 +141,7 @@ class EntityIdsSearchControllerTests extends Specification { def limitValue = "5" def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation([]) def expectedHttpResponseStatus = status().isOk() - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedResponseBody = """ { "entityIds":[] @@ -168,7 +168,7 @@ class EntityIdsSearchControllerTests extends Specification { def limitValue = NO_LIMIT def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation([]) def expectedHttpResponseStatus = status().isOk() - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON def expectedResponseBody = """ { "entityIds":[] @@ -188,4 +188,4 @@ class EntityIdsSearchControllerTests extends Specification { .andExpect(content().contentType(expectedResponseContentType)) .andExpect(content().json(expectedResponseBody, true)) } -} \ No newline at end of file +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy index 16ab5f6e0..280294aa1 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy @@ -31,7 +31,7 @@ import spock.lang.Specification import spock.lang.Unroll import static org.hamcrest.CoreMatchers.containsString -import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8 +import static org.springframework.http.MediaType.APPLICATION_JSON import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.* import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.* @@ -106,7 +106,7 @@ class MetadataFiltersControllerTests extends Specification { 1 * metadataResolverRepository.findByResourceId(_) >> metadataResolver def expectedHttpResponseStatus = status().isOk() - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON when: def result = mockMvc.perform(get("$BASE_URI/foo/Filters")) @@ -127,7 +127,7 @@ class MetadataFiltersControllerTests extends Specification { def expectedResourceId = expectedFilter.resourceId def expectedHttpResponseStatus = status().isOk() - def expectedResponseContentType = APPLICATION_JSON_UTF8 + def expectedResponseContentType = APPLICATION_JSON when: def result = mockMvc.perform(get("$BASE_URI/foo/Filters/$expectedResourceId")) @@ -163,7 +163,7 @@ class MetadataFiltersControllerTests extends Specification { when: def result = mockMvc.perform( post("$BASE_URI/foo/Filters") - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: @@ -208,7 +208,7 @@ class MetadataFiltersControllerTests extends Specification { when: def result = mockMvc.perform( put("$BASE_URI/foo/Filters/$filterUUID") - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: @@ -245,7 +245,7 @@ class MetadataFiltersControllerTests extends Specification { when: def result = mockMvc.perform( put("$BASE_URI/foo/Filters/$filterUUID") - .contentType(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON) .content(postedJsonBody)) then: diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepositoryTest.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepositoryTest.groovy index 741df5ac5..9719ada72 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepositoryTest.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepositoryTest.groovy @@ -29,7 +29,7 @@ import javax.persistence.EntityManager * A highly unnecessary test so that I can check to make sure that persistence is correct for the model */ @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, InternationalizationConfiguration]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, InternationalizationConfiguration, Config]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") @DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy index 43bff31ce..a0ba13aca 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy @@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ContextConfiguration import spock.lang.Specification @@ -34,6 +35,7 @@ import static edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttrib @ContextConfiguration(classes = [CoreShibUiConfiguration, SearchConfiguration, TestConfiguration, InternationalizationConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) class MetadataResolverRepositoryTests extends Specification { @Autowired MetadataResolverRepository metadataResolverRepository diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersControllerIntegrationTests.groovy index b50495b47..5ecb34dc0 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/security/controller/UsersControllerIntegrationTests.groovy @@ -83,7 +83,7 @@ class UsersControllerIntegrationTests extends Specification { then: 'Request completed with HTTP 200 and returned a list of users' result .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(expectedJson, false)) } @@ -106,7 +106,7 @@ class UsersControllerIntegrationTests extends Specification { then: 'Request completed with HTTP 200 and returned one user' result .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(expectedJson, false)) } @@ -156,7 +156,7 @@ class UsersControllerIntegrationTests extends Specification { when: def result = mockMvc.perform(post(RESOURCE_URI) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(JsonOutput.toJson(newUser)) .accept(MediaType.APPLICATION_JSON)) @@ -177,11 +177,11 @@ class UsersControllerIntegrationTests extends Specification { when: mockMvc.perform(post(RESOURCE_URI) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(JsonOutput.toJson(newUser)) .accept(MediaType.APPLICATION_JSON)) def result = mockMvc.perform(post(RESOURCE_URI) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(JsonOutput.toJson(newUser)) .accept(MediaType.APPLICATION_JSON)) @@ -202,7 +202,7 @@ class UsersControllerIntegrationTests extends Specification { when: def result = mockMvc.perform(post(RESOURCE_URI) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(JsonOutput.toJson(newUser)) .accept(MediaType.APPLICATION_JSON)) @@ -212,7 +212,7 @@ class UsersControllerIntegrationTests extends Specification { when: newUser['firstName'] = 'Bob' result = mockMvc.perform(patch("$RESOURCE_URI/$newUser.username") - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(JsonOutput.toJson(newUser)) .accept(MediaType.APPLICATION_JSON)) @@ -232,7 +232,7 @@ class UsersControllerIntegrationTests extends Specification { when: def result = mockMvc.perform(patch("$RESOURCE_URI/$newUser.username") - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content(JsonOutput.toJson(newUser))) then: diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/EmailServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/EmailServiceImplTests.groovy index 6dbfe3f34..148def965 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/EmailServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/EmailServiceImplTests.groovy @@ -10,7 +10,6 @@ import groovy.json.JsonOutput import groovy.json.JsonSlurper import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.boot.test.context.SpringBootTest import org.springframework.core.env.Environment import org.springframework.data.jpa.repository.config.EnableJpaRepositories @@ -23,7 +22,7 @@ import spock.lang.Specification * @author Bill Smith (wsmith@unicon.net) */ @SpringBootTest -@DataJpaTest +//@DataJpaTest @ContextConfiguration(classes=[CoreShibUiConfiguration, EmailConfiguration, TestConfiguration, InternationalizationConfiguration, SearchConfiguration, DevConfig]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/IncommonJPAMetadataResolverServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/IncommonJPAMetadataResolverServiceImplTests.groovy index 08a14feb5..110ebffc4 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/IncommonJPAMetadataResolverServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/IncommonJPAMetadataResolverServiceImplTests.groovy @@ -29,9 +29,8 @@ import spock.lang.Specification import static edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers.* -@SpringBootTest @DataJpaTest -@ContextConfiguration(classes = [CoreShibUiConfiguration, SearchConfiguration, InternationalizationConfiguration]) +@ContextConfiguration(classes = [CoreShibUiConfiguration, SearchConfiguration, InternationalizationConfiguration, TestConfig]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") class IncommonJPAMetadataResolverServiceImplTests extends Specification { diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy index 73ace1205..9470b6046 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy @@ -30,14 +30,12 @@ import net.shibboleth.ext.spring.resource.ResourceHelper import net.shibboleth.utilities.java.support.resolver.CriteriaSet import org.joda.time.DateTime import org.opensaml.core.criterion.EntityIdCriterion -import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver import org.opensaml.saml.metadata.resolver.MetadataResolver import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest -import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.context.TestConfiguration import org.springframework.context.annotation.Bean import org.springframework.core.io.ClassPathResource @@ -50,16 +48,10 @@ import spock.lang.Ignore import spock.lang.Specification import spock.lang.Unroll -import javax.xml.transform.OutputKeys -import javax.xml.transform.TransformerFactory -import javax.xml.transform.dom.DOMSource -import javax.xml.transform.stream.StreamResult - import static edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers.generatedXmlIsTheSameAsExpectedXml -@SpringBootTest @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, MetadataResolverConverterConfiguration, SearchConfiguration, InternationalizationConfiguration, PlaceholderResolverComponentsConfiguration]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, MetadataResolverConverterConfiguration, SearchConfiguration, InternationalizationConfiguration, PlaceholderResolverComponentsConfiguration, Config]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) diff --git a/beacon/build.gradle b/beacon/build.gradle deleted file mode 100644 index a0d845ead..000000000 --- a/beacon/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -allprojects { - group = 'edu.internet2.tap.beacon' - version = '1.0.0-SNAPSHOT' -} \ No newline at end of file diff --git a/beacon/core/build.gradle b/beacon/core/build.gradle index 5c9689ebd..c80df0931 100644 --- a/beacon/core/build.gradle +++ b/beacon/core/build.gradle @@ -1,13 +1,13 @@ import org.springframework.boot.gradle.plugin.SpringBootPlugin plugins { - id 'org.springframework.boot' version '2.0.0.RELEASE' apply false + id 'org.springframework.boot' version '2.4.2' apply false id 'io.spring.dependency-management' version '1.0.6.RELEASE' } apply plugin: 'groovy' -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = 11 +targetCompatibility = 11 repositories { jcenter() @@ -21,8 +21,8 @@ dependencyManagement { dependencies { testCompile "org.springframework.boot:spring-boot-starter-test" - testCompile "org.spockframework:spock-core:1.1-groovy-2.4" - testCompile "org.spockframework:spock-spring:1.1-groovy-2.4" + testCompile "org.spockframework:spock-core:1.3-groovy-2.5" + testCompile "org.spockframework:spock-spring:1.3-groovy-2.5" testCompile 'org.junit.jupiter:junit-jupiter-api:5.5.2' testCompile 'org.junit.jupiter:junit-jupiter-engine:5.5.2' @@ -30,4 +30,4 @@ dependencies { jar { archiveName = "beacon-core-${version}.jar" -} \ No newline at end of file +} diff --git a/beacon/gradle.properties b/beacon/gradle.properties new file mode 100644 index 000000000..23dbf7481 --- /dev/null +++ b/beacon/gradle.properties @@ -0,0 +1,2 @@ +group=edu.internet2.tap.beacon +version=1.0.0-SNAPSHOT diff --git a/beacon/spring/build.gradle b/beacon/spring/build.gradle index bb895f0e6..61ab07be5 100644 --- a/beacon/spring/build.gradle +++ b/beacon/spring/build.gradle @@ -6,8 +6,8 @@ plugins { } apply plugin: 'java' -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = 11 +targetCompatibility = 11 repositories { jcenter() diff --git a/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/BeaconPublishingConfiguration.java b/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/BeaconPublishingConfiguration.java index 79e073641..f0324bacd 100644 --- a/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/BeaconPublishingConfiguration.java +++ b/beacon/spring/src/main/java/edu/internet2/tap/beacon/configuration/BeaconPublishingConfiguration.java @@ -49,7 +49,7 @@ public BeaconPublishingTask(DefaultBeaconPublisher beaconPublisher) { } //Cron is based on the spec defined here: https://spaces.at.internet2.edu/display/TWGH/TIER+Instrumentation+-+The+TIER+Beacon - @Scheduled(cron = "0 ${random.int[0,59]} ${random.int[0,3]} ? * *}") + @Scheduled(cron = "0 ${random.int[0,59]} ${random.int[0,3]} ? * *") @Async void publish() { logger.debug("Publishing payload: {} to beacon endpoint: {}", diff --git a/build.gradle b/build.gradle index a651a1093..ba9ceaa9d 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,3 @@ githubRelease { } afterReleaseBuild.dependsOn project.getTasksByName('githubRelease', false) - -task wrapper(type: Wrapper) { - gradleVersion = '4.8.1' -} diff --git a/gradle.properties b/gradle.properties index 5952542e5..779b57b73 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,15 +1,15 @@ name=shibui group=edu.internet2.tier.shibboleth.admin.ui -version=1.8.0-RC1-SNAPSHOT +version=2.0.0-RC1-SNAPSHOT -shibboleth.version=3.4.0 -opensaml.version=3.4.0 +shibboleth.version=3.4.4 +opensaml.version=3.4.3 -spring-boot.version=2.0.0.RELEASE +spring-boot.version=2.4.2 hibernate.version=5.3.14.Final -lucene.version=7.2.1 +lucene.version=8.1.1 org.gradle.jvmargs=-Xmx1g -XX:-UseGCOverheadLimit @@ -18,3 +18,4 @@ i2.github.token= i2.github.owner=TIER i2.github.repo=shib-idp-ui i2.github.apiEndpoint=https://github.internet2.edu/api/v3 + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ca78035ef..87b738cbd 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6ca65f865..2a563242c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Mon Nov 26 11:20:36 CST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip diff --git a/gradlew b/gradlew index cccdd3d51..af6708ff2 100755 --- a/gradlew +++ b/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index f9553162f..6d57edc70 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/pac4j-module/build.gradle b/pac4j-module/build.gradle index d493d2437..2d952a4c8 100644 --- a/pac4j-module/build.gradle +++ b/pac4j-module/build.gradle @@ -1,12 +1,12 @@ plugins { id 'groovy' id 'jacoco' - id 'org.springframework.boot' version '2.0.0.RELEASE' apply false - id 'io.spring.dependency-management' version '1.0.6.RELEASE' + id 'org.springframework.boot' version '2.1.5.RELEASE' apply false + id 'io.spring.dependency-management' version '1.0.7.RELEASE' } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = 11 +targetCompatibility = 11 repositories { jcenter() @@ -34,8 +34,8 @@ dependencies { testCompile project(':backend') testCompile "org.springframework.boot:spring-boot-starter-test" - testCompile "org.spockframework:spock-core:1.1-groovy-2.4" - testCompile "org.spockframework:spock-spring:1.1-groovy-2.4" + testCompile "org.spockframework:spock-core:1.3-groovy-2.5" + testCompile "org.spockframework:spock-spring:1.3-groovy-2.5" annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" -} \ No newline at end of file +} diff --git a/ui/build.gradle b/ui/build.gradle index 64fe2e561..34827354e 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -1,6 +1,6 @@ plugins { id 'base' - id 'com.moowork.node' version '1.3.1' + id 'com.github.node-gradle.node' version '2.2.4' } node { diff --git a/ui/package-lock.json b/ui/package-lock.json index 922d700dd..421964f7a 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -4989,7 +4989,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -17186,7 +17187,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } }