From 09252650c9a740e4bdd9c483da0116a1a852eec0 Mon Sep 17 00:00:00 2001 From: Tahmid Ahmed Date: Wed, 4 Nov 2026 00:43:11 -0500 Subject: [PATCH 1/3] DINO-1164: Update maven wrapper. Remove LASS calls from main backend and replaced it with LAS. the main backend no longer tries to reconcile the token within itself anymore. CI receives an empty shell so that we dont have to juggle with authentication in CI/CD --- .mvn/wrapper/MavenWrapperDownloader.java | 117 --- .mvn/wrapper/maven-wrapper.jar | Bin 50710 -> 63093 bytes .mvn/wrapper/maven-wrapper.properties | 6 +- .sops.yaml | 8 +- Justfile | 6 +- .../src/generate.py | 13 - .../grpc/leetcodeauth/v1/GetTokenRequest.java | 361 +++++++++ .../v1/GetTokenRequestOrBuilder.java | 12 + .../leetcodeauth/v1/GetTokenResponse.java} | 310 ++++---- .../v1/GetTokenResponseOrBuilder.java | 36 + .../grpc/leetcodeauth/v1/LeetcodeAuth.java | 103 +++ .../v1/LeetcodeAuthServiceGrpc.java | 450 +++++++++++ .../leetcodeauth/v1/RefreshTokenRequest.java | 361 +++++++++ .../v1/RefreshTokenRequestOrBuilder.java | 12 + .../leetcodeauth/v1/RefreshTokenResponse.java | 456 ++++++++++++ .../v1/RefreshTokenResponseOrBuilder.java | 22 + .../auth/v1/AuthenticateRequestOrBuilder.java | 36 - .../auth/v1/AuthenticateResponse.java | 645 ---------------- .../v1/AuthenticateResponseOrBuilder.java | 36 - .../v1/LeetcodeAuthStealerServiceGrpc.java | 329 -------- .../LeetcodeAuthStealerServiceOuterClass.java | 79 -- mvnw | 362 ++++----- mvnw.cmd | 388 +++++----- pom.xml | 23 +- .../codebloom/api/admin/AdminController.java | 10 +- .../common/leetcode/LeetcodeClientImpl.java | 45 +- .../auth/AuthenticationCredentials.java | 4 +- .../auth/CiLeetcodeAuthenticationService.java | 18 + .../DefaultLeetcodeAuthenticationService.java | 39 + .../DirectLeetcodeAuthenticationClient.java | 36 - ...eetcodeAuthenticationClientProperties.java | 8 - .../GitHubLeetcodeAuthenticationClient.java | 25 - ...eetcodeAuthenticationClientProperties.java | 8 - .../auth/LeetcodeAuthenticationClient.java | 7 - .../auth/LeetcodeAuthenticationService.java | 8 + .../config/GrpcClientConfiguration.java | 20 +- ...deAuthServiceGrpcClientConfiguration.java} | 4 +- .../playwright/PlaywrightClient.java | 101 --- .../scheduled/auth/CodeExtractor.java | 18 - .../scheduled/auth/LeetcodeAuthStealer.java | 178 ----- src/main/resources/application.yml | 8 +- .../api/admin/AdminControllerTest.java | 11 +- .../common/db/repos/BaseRepositoryTest.java | 4 +- .../LeetcodeClientCircuitBreakerTest.java | 10 +- .../common/leetcode/LeetcodeClientTest.java | 27 +- ...irectLeetcodeAuthenticationClientTest.java | 49 -- ...itHubLeetcodeAuthenticationClientTest.java | 37 - .../auth/LeetcodeAuthStealerTest.java | 704 ------------------ 48 files changed, 2545 insertions(+), 3005 deletions(-) delete mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenRequest.java create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenRequestOrBuilder.java rename lib/{leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateRequest.java => leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenResponse.java} (60%) create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenResponseOrBuilder.java create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/LeetcodeAuth.java create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/LeetcodeAuthServiceGrpc.java create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenRequest.java create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenRequestOrBuilder.java create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenResponse.java create mode 100644 lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenResponseOrBuilder.java delete mode 100644 lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateRequestOrBuilder.java delete mode 100644 lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateResponse.java delete mode 100644 lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateResponseOrBuilder.java delete mode 100644 lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/LeetcodeAuthStealerServiceGrpc.java delete mode 100644 lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/LeetcodeAuthStealerServiceOuterClass.java create mode 100644 src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/CiLeetcodeAuthenticationService.java create mode 100644 src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DefaultLeetcodeAuthenticationService.java delete mode 100644 src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClient.java delete mode 100644 src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClientProperties.java delete mode 100644 src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClient.java delete mode 100644 src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClientProperties.java delete mode 100644 src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/LeetcodeAuthenticationClient.java create mode 100644 src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/LeetcodeAuthenticationService.java rename src/main/java/org/patinanetwork/codebloom/config/{LeetcodeAuthStealerGrpcClientConfiguration.java => LeetcodeAuthServiceGrpcClientConfiguration.java} (59%) delete mode 100644 src/main/java/org/patinanetwork/codebloom/scheduled/auth/CodeExtractor.java delete mode 100644 src/main/java/org/patinanetwork/codebloom/scheduled/auth/LeetcodeAuthStealer.java delete mode 100644 src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClientTest.java delete mode 100644 src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClientTest.java delete mode 100644 src/test/java/org/patinanetwork/codebloom/scheduled/auth/LeetcodeAuthStealerTest.java diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2..000000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar index 2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054..eebc3c18b4e0bce4a2a9e66be24c4a410f17a1fa 100644 GIT binary patch literal 63093 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 _ohw3Ut=#j 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 literal 50710 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 EfAhh=DF6Tf diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 642d572ce..970a3d02d 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,4 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar +wrapperVersion=3.3.4 +distributionType=bin +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar diff --git a/.sops.yaml b/.sops.yaml index 77cbfe524..455dd475f 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -1,6 +1,6 @@ stores: - yaml: - indent: 2 + yaml: + indent: 2 creation_rules: - - path_regex: .env.shared.yaml - azure_keyvault: "https://sops-master.vault.azure.net/keys/sops-key/" + - path_regex: .env.shared.yaml + azure_keyvault: "https://sops-master.vault.azure.net/keys/sops-key/" diff --git a/Justfile b/Justfile index b8a0bf52f..5020e9359 100644 --- a/Justfile +++ b/Justfile @@ -42,9 +42,9 @@ las-dev *args: lass-dev *args: cd ./internal/leetcode-auth-stealer-service && uv sync && GRPC_REFLECTION=true GRPC_VERBOSITY=ERROR uv run src/server.py -# Generate the leetcode auth stealer gRPC stubs for the main codebloom service -lass-gen *args: - cd ./internal/leetcode-auth-stealer-service && uv sync && uv run src/generate.py +# Generate the leetcode auth service gRPC stubs for the main codebloom service +las-gen *args: + rm -rf lib/leetcode-auth-service/src/main/java && bash ./mvnw -q protobuf:compile protobuf:compile-custom {{args}} # Run the backend Spring server with an exposed debugger at :5005 backend-dev-debug *args: diff --git a/internal/leetcode-auth-stealer-service/src/generate.py b/internal/leetcode-auth-stealer-service/src/generate.py index d49e0eeeb..5d0612a2d 100644 --- a/internal/leetcode-auth-stealer-service/src/generate.py +++ b/internal/leetcode-auth-stealer-service/src/generate.py @@ -8,10 +8,8 @@ python_output = root / "src" / "generated" repo = root.parent.parent -java_output = repo / "lib" / "leetcode-auth-stealer-service" / "src" / "main" / "java" python_output.mkdir(parents=True, exist_ok=True) -java_output.mkdir(parents=True, exist_ok=True) subprocess.run( [ @@ -26,14 +24,3 @@ ], check=True, ) - -subprocess.run( - [ - "protoc", - f"-I{proto_dir}", - f"--java_out={java_output}", - f"--grpc-java_out={java_output}", - str(proto_dir / "LeetcodeAuthStealerService.proto"), - ], - check=True, -) diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenRequest.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenRequest.java new file mode 100644 index 000000000..f9fd5fb55 --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenRequest.java @@ -0,0 +1,361 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: v1/leetcode_auth.proto +// Protobuf Java Version: 4.36.2 + +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +/** + * Protobuf type {@code leetcodeauth.GetTokenRequest} + */ +@com.google.protobuf.Generated +public final class GetTokenRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:leetcodeauth.GetTokenRequest) + GetTokenRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 36, + /* patch= */ 2, + /* suffix= */ "", + "GetTokenRequest"); + } + // Use GetTokenRequest.newBuilder() to construct. + private GetTokenRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private GetTokenRequest() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenRequest_descriptor; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.class, org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.Builder.class); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getUnknownFields().writeTo(output); + } + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest)) { + return super.equals(obj); + } + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest other = (org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest) obj; + + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code leetcodeauth.GetTokenRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:leetcodeauth.GetTokenRequest) + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.class, org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.Builder.class); + } + + // Construct using org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenRequest_descriptor; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest getDefaultInstanceForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest build() { + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest buildPartial() { + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest result = new org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest(this); + onBuilt(); + return result; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest) { + return mergeFrom((org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest other) { + if (other == org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.getDefaultInstance()) return this; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + java.util.Objects.requireNonNull(extensionRegistry); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + // @@protoc_insertion_point(builder_scope:leetcodeauth.GetTokenRequest) + } + + // @@protoc_insertion_point(class_scope:leetcodeauth.GetTokenRequest) + private static final org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest(); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public GetTokenRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenRequestOrBuilder.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenRequestOrBuilder.java new file mode 100644 index 000000000..c664906cc --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenRequestOrBuilder.java @@ -0,0 +1,12 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: v1/leetcode_auth.proto +// Protobuf Java Version: 4.36.2 + +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +@com.google.protobuf.Generated +public interface GetTokenRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:leetcodeauth.GetTokenRequest) + com.google.protobuf.MessageOrBuilder { +} diff --git a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateRequest.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenResponse.java similarity index 60% rename from lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateRequest.java rename to lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenResponse.java index 34c505359..fdfe26abf 100644 --- a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateRequest.java +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenResponse.java @@ -1,18 +1,18 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE -// source: LeetcodeAuthStealerService.proto +// source: v1/leetcode_auth.proto // Protobuf Java Version: 4.36.2 -package org.patinanetwork.codebloom.grpc.leetcode.auth.v1; +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; /** - * Protobuf type {@code codebloom.leetcode.auth.v1.AuthenticateRequest} + * Protobuf type {@code leetcodeauth.GetTokenResponse} */ @com.google.protobuf.Generated -public final class AuthenticateRequest extends +public final class GetTokenResponse extends com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:codebloom.leetcode.auth.v1.AuthenticateRequest) - AuthenticateRequestOrBuilder { + // @@protoc_insertion_point(message_implements:leetcodeauth.GetTokenResponse) + GetTokenResponseOrBuilder { private static final long serialVersionUID = 0L; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( @@ -21,107 +21,107 @@ public final class AuthenticateRequest extends /* minor= */ 36, /* patch= */ 2, /* suffix= */ "", - "AuthenticateRequest"); + "GetTokenResponse"); } - // Use AuthenticateRequest.newBuilder() to construct. - private AuthenticateRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + // Use GetTokenResponse.newBuilder() to construct. + private GetTokenResponse(com.google.protobuf.GeneratedMessage.Builder builder) { super(builder); } - private AuthenticateRequest() { - login_ = ""; - password_ = ""; + private GetTokenResponse() { + token_ = ""; + csrf_ = ""; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_descriptor; + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenResponse_descriptor; } @java.lang.Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_descriptor; + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenResponse_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_fieldAccessorTable + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenResponse_fieldAccessorTable .ensureFieldAccessorsInitialized( - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.class, org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.Builder.class); + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.class, org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.Builder.class); } - public static final int LOGIN_FIELD_NUMBER = 1; + public static final int TOKEN_FIELD_NUMBER = 1; @SuppressWarnings("serial") - private volatile java.lang.Object login_ = ""; + private volatile java.lang.Object token_ = ""; /** - * string login = 1; - * @return The login. + * string token = 1; + * @return The token. */ @java.lang.Override - public java.lang.String getLogin() { - java.lang.Object ref = login_; + public java.lang.String getToken() { + java.lang.Object ref = token_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); - login_ = s; + token_ = s; return s; } } /** - * string login = 1; - * @return The bytes for login. + * string token = 1; + * @return The bytes for token. */ @java.lang.Override public com.google.protobuf.ByteString - getLoginBytes() { - java.lang.Object ref = login_; + getTokenBytes() { + java.lang.Object ref = token_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); - login_ = b; + token_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } - public static final int PASSWORD_FIELD_NUMBER = 2; + public static final int CSRF_FIELD_NUMBER = 2; @SuppressWarnings("serial") - private volatile java.lang.Object password_ = ""; + private volatile java.lang.Object csrf_ = ""; /** - * string password = 2; - * @return The password. + * string csrf = 2; + * @return The csrf. */ @java.lang.Override - public java.lang.String getPassword() { - java.lang.Object ref = password_; + public java.lang.String getCsrf() { + java.lang.Object ref = csrf_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); - password_ = s; + csrf_ = s; return s; } } /** - * string password = 2; - * @return The bytes for password. + * string csrf = 2; + * @return The bytes for csrf. */ @java.lang.Override public com.google.protobuf.ByteString - getPasswordBytes() { - java.lang.Object ref = password_; + getCsrfBytes() { + java.lang.Object ref = csrf_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); - password_ = b; + csrf_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; @@ -142,21 +142,21 @@ public final boolean isInitialized() { @java.lang.Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(login_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, login_); + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(token_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, token_); } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(password_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, password_); + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(csrf_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, csrf_); } getUnknownFields().writeTo(output); } private int computeSerializedSize_0() { int size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(login_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, login_); + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(token_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, token_); } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(password_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, password_); + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(csrf_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, csrf_); } return size; } @@ -177,15 +177,15 @@ public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } - if (!(obj instanceof org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest)) { + if (!(obj instanceof org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse)) { return super.equals(obj); } - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest other = (org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest) obj; + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse other = (org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse) obj; - if (!getLogin() - .equals(other.getLogin())) return false; - if (!getPassword() - .equals(other.getPassword())) return false; + if (!getToken() + .equals(other.getToken())) return false; + if (!getCsrf() + .equals(other.getCsrf())) return false; if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @@ -197,53 +197,53 @@ public int hashCode() { } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + LOGIN_FIELD_NUMBER; - hash = (53 * hash) + getLogin().hashCode(); - hash = (37 * hash) + PASSWORD_FIELD_NUMBER; - hash = (53 * hash) + getPassword().hashCode(); + hash = (37 * hash) + TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getToken().hashCode(); + hash = (37 * hash) + CSRF_FIELD_NUMBER; + hash = (53 * hash) + getCsrf().hashCode(); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom(byte[] data) + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom(java.io.InputStream input) + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -251,26 +251,26 @@ public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequ .parseWithIOException(PARSER, input, extensionRegistry); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseDelimitedFrom(java.io.InputStream input) + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseDelimitedFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest parseFrom( + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -283,7 +283,7 @@ public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequ public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } - public static Builder newBuilder(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest prototype) { + public static Builder newBuilder(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @java.lang.Override @@ -299,26 +299,26 @@ protected Builder newBuilderForType( return builder; } /** - * Protobuf type {@code codebloom.leetcode.auth.v1.AuthenticateRequest} + * Protobuf type {@code leetcodeauth.GetTokenResponse} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:codebloom.leetcode.auth.v1.AuthenticateRequest) - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequestOrBuilder { + // @@protoc_insertion_point(builder_implements:leetcodeauth.GetTokenResponse) + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponseOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_descriptor; + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenResponse_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_fieldAccessorTable + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenResponse_fieldAccessorTable .ensureFieldAccessorsInitialized( - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.class, org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.Builder.class); + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.class, org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.Builder.class); } - // Construct using org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.newBuilder() + // Construct using org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.newBuilder() private Builder() { } @@ -332,25 +332,25 @@ private Builder( public Builder clear() { super.clear(); bitField0_ = 0; - login_ = ""; - password_ = ""; + token_ = ""; + csrf_ = ""; return this; } @java.lang.Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_descriptor; + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_GetTokenResponse_descriptor; } @java.lang.Override - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest getDefaultInstanceForType() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.getDefaultInstance(); + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse getDefaultInstanceForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.getDefaultInstance(); } @java.lang.Override - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest build() { - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest result = buildPartial(); + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse build() { + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } @@ -358,42 +358,42 @@ public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest bui } @java.lang.Override - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest buildPartial() { - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest result = new org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest(this); + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse buildPartial() { + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse result = new org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse(this); if (bitField0_ != 0) { buildPartial0(result); } onBuilt(); return result; } - private void buildPartial0(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest result) { + private void buildPartial0(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse result) { int from_bitField0_ = bitField0_; if (((from_bitField0_ & 0x00000001) != 0)) { - result.login_ = login_; + result.token_ = token_; } if (((from_bitField0_ & 0x00000002) != 0)) { - result.password_ = password_; + result.csrf_ = csrf_; } } @java.lang.Override public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest) { - return mergeFrom((org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest)other); + if (other instanceof org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse) { + return mergeFrom((org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse)other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest other) { - if (other == org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.getDefaultInstance()) return this; - if (!other.getLogin().isEmpty()) { - login_ = other.login_; + public Builder mergeFrom(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse other) { + if (other == org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.getDefaultInstance()) return this; + if (!other.getToken().isEmpty()) { + token_ = other.token_; bitField0_ |= 0x00000001; onChanged(); } - if (!other.getPassword().isEmpty()) { - password_ = other.password_; + if (!other.getCsrf().isEmpty()) { + csrf_ = other.csrf_; bitField0_ |= 0x00000002; onChanged(); } @@ -422,12 +422,12 @@ public Builder mergeFrom( done = true; break; case 10: { - login_ = input.readStringRequireUtf8(); + token_ = input.readStringRequireUtf8(); bitField0_ |= 0x00000001; break; } // case 10 case 18: { - password_ = input.readStringRequireUtf8(); + csrf_ = input.readStringRequireUtf8(); bitField0_ |= 0x00000002; break; } // case 18 @@ -448,167 +448,167 @@ public Builder mergeFrom( } private int bitField0_; - private java.lang.Object login_ = ""; + private java.lang.Object token_ = ""; /** - * string login = 1; - * @return The login. + * string token = 1; + * @return The token. */ - public java.lang.String getLogin() { - java.lang.Object ref = login_; + public java.lang.String getToken() { + java.lang.Object ref = token_; if (!(ref instanceof java.lang.String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); - login_ = s; + token_ = s; return s; } else { return (java.lang.String) ref; } } /** - * string login = 1; - * @return The bytes for login. + * string token = 1; + * @return The bytes for token. */ public com.google.protobuf.ByteString - getLoginBytes() { - java.lang.Object ref = login_; + getTokenBytes() { + java.lang.Object ref = token_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); - login_ = b; + token_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** - * string login = 1; - * @param value The login to set. + * string token = 1; + * @param value The token to set. * @return This builder for chaining. */ - public Builder setLogin( + public Builder setToken( java.lang.String value) { java.util.Objects.requireNonNull(value); - login_ = value; + token_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } /** - * string login = 1; + * string token = 1; * @return This builder for chaining. */ - public Builder clearLogin() { - login_ = getDefaultInstance().getLogin(); + public Builder clearToken() { + token_ = getDefaultInstance().getToken(); bitField0_ = (bitField0_ & ~0x00000001); onChanged(); return this; } /** - * string login = 1; - * @param value The bytes for login to set. + * string token = 1; + * @param value The bytes for token to set. * @return This builder for chaining. */ - public Builder setLoginBytes( + public Builder setTokenBytes( com.google.protobuf.ByteString value) { java.util.Objects.requireNonNull(value); checkByteStringIsUtf8(value); - login_ = value; + token_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } - private java.lang.Object password_ = ""; + private java.lang.Object csrf_ = ""; /** - * string password = 2; - * @return The password. + * string csrf = 2; + * @return The csrf. */ - public java.lang.String getPassword() { - java.lang.Object ref = password_; + public java.lang.String getCsrf() { + java.lang.Object ref = csrf_; if (!(ref instanceof java.lang.String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); - password_ = s; + csrf_ = s; return s; } else { return (java.lang.String) ref; } } /** - * string password = 2; - * @return The bytes for password. + * string csrf = 2; + * @return The bytes for csrf. */ public com.google.protobuf.ByteString - getPasswordBytes() { - java.lang.Object ref = password_; + getCsrfBytes() { + java.lang.Object ref = csrf_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); - password_ = b; + csrf_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** - * string password = 2; - * @param value The password to set. + * string csrf = 2; + * @param value The csrf to set. * @return This builder for chaining. */ - public Builder setPassword( + public Builder setCsrf( java.lang.String value) { java.util.Objects.requireNonNull(value); - password_ = value; + csrf_ = value; bitField0_ |= 0x00000002; onChanged(); return this; } /** - * string password = 2; + * string csrf = 2; * @return This builder for chaining. */ - public Builder clearPassword() { - password_ = getDefaultInstance().getPassword(); + public Builder clearCsrf() { + csrf_ = getDefaultInstance().getCsrf(); bitField0_ = (bitField0_ & ~0x00000002); onChanged(); return this; } /** - * string password = 2; - * @param value The bytes for password to set. + * string csrf = 2; + * @param value The bytes for csrf to set. * @return This builder for chaining. */ - public Builder setPasswordBytes( + public Builder setCsrfBytes( com.google.protobuf.ByteString value) { java.util.Objects.requireNonNull(value); checkByteStringIsUtf8(value); - password_ = value; + csrf_ = value; bitField0_ |= 0x00000002; onChanged(); return this; } - // @@protoc_insertion_point(builder_scope:codebloom.leetcode.auth.v1.AuthenticateRequest) + // @@protoc_insertion_point(builder_scope:leetcodeauth.GetTokenResponse) } - // @@protoc_insertion_point(class_scope:codebloom.leetcode.auth.v1.AuthenticateRequest) - private static final org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest DEFAULT_INSTANCE; + // @@protoc_insertion_point(class_scope:leetcodeauth.GetTokenResponse) + private static final org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse DEFAULT_INSTANCE; static { - DEFAULT_INSTANCE = new org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest(); + DEFAULT_INSTANCE = new org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse(); } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest getDefaultInstance() { + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse getDefaultInstance() { return DEFAULT_INSTANCE; } - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { @java.lang.Override - public AuthenticateRequest parsePartialFrom( + public GetTokenResponse parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { @@ -627,17 +627,17 @@ public AuthenticateRequest parsePartialFrom( } }; - public static com.google.protobuf.Parser parser() { + public static com.google.protobuf.Parser parser() { return PARSER; } @java.lang.Override - public com.google.protobuf.Parser getParserForType() { + public com.google.protobuf.Parser getParserForType() { return PARSER; } @java.lang.Override - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest getDefaultInstanceForType() { + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse getDefaultInstanceForType() { return DEFAULT_INSTANCE; } diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenResponseOrBuilder.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenResponseOrBuilder.java new file mode 100644 index 000000000..f44254289 --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/GetTokenResponseOrBuilder.java @@ -0,0 +1,36 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: v1/leetcode_auth.proto +// Protobuf Java Version: 4.36.2 + +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +@com.google.protobuf.Generated +public interface GetTokenResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:leetcodeauth.GetTokenResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * string token = 1; + * @return The token. + */ + java.lang.String getToken(); + /** + * string token = 1; + * @return The bytes for token. + */ + com.google.protobuf.ByteString + getTokenBytes(); + + /** + * string csrf = 2; + * @return The csrf. + */ + java.lang.String getCsrf(); + /** + * string csrf = 2; + * @return The bytes for csrf. + */ + com.google.protobuf.ByteString + getCsrfBytes(); +} diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/LeetcodeAuth.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/LeetcodeAuth.java new file mode 100644 index 000000000..718ed4411 --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/LeetcodeAuth.java @@ -0,0 +1,103 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: v1/leetcode_auth.proto +// Protobuf Java Version: 4.36.2 + +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +@com.google.protobuf.Generated +public final class LeetcodeAuth extends com.google.protobuf.GeneratedFile { + private LeetcodeAuth() {} + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 36, + /* patch= */ 2, + /* suffix= */ "", + "LeetcodeAuth"); + } + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_leetcodeauth_GetTokenRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_leetcodeauth_GetTokenRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_leetcodeauth_GetTokenResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_leetcodeauth_GetTokenResponse_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_leetcodeauth_RefreshTokenRequest_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_leetcodeauth_RefreshTokenRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_leetcodeauth_RefreshTokenResponse_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_leetcodeauth_RefreshTokenResponse_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static final com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\026v1/leetcode_auth.proto\022\014leetcodeauth\"\021" + + "\n\017GetTokenRequest\"/\n\020GetTokenResponse\022\r\n" + + "\005token\030\001 \001(\t\022\014\n\004csrf\030\002 \001(\t\"\025\n\023RefreshTok" + + "enRequest\"\'\n\024RefreshTokenResponse\022\017\n\007sta" + + "rted\030\001 \001(\0102\267\001\n\023LeetcodeAuthService\022I\n\010ge" + + "tToken\022\035.leetcodeauth.GetTokenRequest\032\036." + + "leetcodeauth.GetTokenResponse\022U\n\014refresh" + + "Token\022!.leetcodeauth.RefreshTokenRequest" + + "\032\".leetcodeauth.RefreshTokenResponseBo\n0" + + "org.patinanetwork.codebloom.grpc.leetcod" + + "eauth.v1P\001Z9patinanetwork.org/grpc/leetc" + + "ode-auth-service;leetcodeauthb\006proto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_leetcodeauth_GetTokenRequest_descriptor = + getDescriptor().getMessageType(0); + internal_static_leetcodeauth_GetTokenRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_leetcodeauth_GetTokenRequest_descriptor, + new java.lang.String[] { }); + internal_static_leetcodeauth_GetTokenResponse_descriptor = + getDescriptor().getMessageType(1); + internal_static_leetcodeauth_GetTokenResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_leetcodeauth_GetTokenResponse_descriptor, + new java.lang.String[] { "Token", "Csrf", }); + internal_static_leetcodeauth_RefreshTokenRequest_descriptor = + getDescriptor().getMessageType(2); + internal_static_leetcodeauth_RefreshTokenRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_leetcodeauth_RefreshTokenRequest_descriptor, + new java.lang.String[] { }); + internal_static_leetcodeauth_RefreshTokenResponse_descriptor = + getDescriptor().getMessageType(3); + internal_static_leetcodeauth_RefreshTokenResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_leetcodeauth_RefreshTokenResponse_descriptor, + new java.lang.String[] { "Started", }); + descriptor.resolveAllFeaturesImmutable(); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/LeetcodeAuthServiceGrpc.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/LeetcodeAuthServiceGrpc.java new file mode 100644 index 000000000..601ff3da4 --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/LeetcodeAuthServiceGrpc.java @@ -0,0 +1,450 @@ +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@io.grpc.stub.annotations.GrpcGenerated +public final class LeetcodeAuthServiceGrpc { + + private LeetcodeAuthServiceGrpc() {} + + public static final java.lang.String SERVICE_NAME = "leetcodeauth.LeetcodeAuthService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getGetTokenMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getToken", + requestType = org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.class, + responseType = org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetTokenMethod() { + io.grpc.MethodDescriptor getGetTokenMethod; + if ((getGetTokenMethod = LeetcodeAuthServiceGrpc.getGetTokenMethod) == null) { + synchronized (LeetcodeAuthServiceGrpc.class) { + if ((getGetTokenMethod = LeetcodeAuthServiceGrpc.getGetTokenMethod) == null) { + LeetcodeAuthServiceGrpc.getGetTokenMethod = getGetTokenMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getToken")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse.getDefaultInstance())) + .setSchemaDescriptor(new LeetcodeAuthServiceMethodDescriptorSupplier("getToken")) + .build(); + } + } + } + return getGetTokenMethod; + } + + private static volatile io.grpc.MethodDescriptor getRefreshTokenMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "refreshToken", + requestType = org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.class, + responseType = org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getRefreshTokenMethod() { + io.grpc.MethodDescriptor getRefreshTokenMethod; + if ((getRefreshTokenMethod = LeetcodeAuthServiceGrpc.getRefreshTokenMethod) == null) { + synchronized (LeetcodeAuthServiceGrpc.class) { + if ((getRefreshTokenMethod = LeetcodeAuthServiceGrpc.getRefreshTokenMethod) == null) { + LeetcodeAuthServiceGrpc.getRefreshTokenMethod = getRefreshTokenMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "refreshToken")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.getDefaultInstance())) + .setSchemaDescriptor(new LeetcodeAuthServiceMethodDescriptorSupplier("refreshToken")) + .build(); + } + } + } + return getRefreshTokenMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static LeetcodeAuthServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LeetcodeAuthServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LeetcodeAuthServiceStub(channel, callOptions); + } + }; + return LeetcodeAuthServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports all types of calls on the service + */ + public static LeetcodeAuthServiceBlockingV2Stub newBlockingV2Stub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LeetcodeAuthServiceBlockingV2Stub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LeetcodeAuthServiceBlockingV2Stub(channel, callOptions); + } + }; + return LeetcodeAuthServiceBlockingV2Stub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static LeetcodeAuthServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LeetcodeAuthServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LeetcodeAuthServiceBlockingStub(channel, callOptions); + } + }; + return LeetcodeAuthServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static LeetcodeAuthServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LeetcodeAuthServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LeetcodeAuthServiceFutureStub(channel, callOptions); + } + }; + return LeetcodeAuthServiceFutureStub.newStub(factory, channel); + } + + /** + */ + public interface AsyncService { + + /** + *
+     * may return NOT_FOUND until the first refresh succeeds.
+     * 
+ */ + default void getToken(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetTokenMethod(), responseObserver); + } + + /** + *
+     * Starts a refresh in the background and returns immediately. Calls made
+     * while a refresh is running are ignored. The stored credentials keep being
+     * served until a refresh succeeds.
+     * 
+ */ + default void refreshToken(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getRefreshTokenMethod(), responseObserver); + } + } + + /** + * Base class for the server implementation of the service LeetcodeAuthService. + */ + public static abstract class LeetcodeAuthServiceImplBase + implements io.grpc.BindableService, AsyncService { + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return LeetcodeAuthServiceGrpc.bindService(this); + } + } + + /** + * A stub to allow clients to do asynchronous rpc calls to service LeetcodeAuthService. + */ + public static final class LeetcodeAuthServiceStub + extends io.grpc.stub.AbstractAsyncStub { + private LeetcodeAuthServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected LeetcodeAuthServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LeetcodeAuthServiceStub(channel, callOptions); + } + + /** + *
+     * may return NOT_FOUND until the first refresh succeeds.
+     * 
+ */ + public void getToken(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetTokenMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
+     * Starts a refresh in the background and returns immediately. Calls made
+     * while a refresh is running are ignored. The stored credentials keep being
+     * served until a refresh succeeds.
+     * 
+ */ + public void refreshToken(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getRefreshTokenMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + * A stub to allow clients to do synchronous rpc calls to service LeetcodeAuthService. + */ + public static final class LeetcodeAuthServiceBlockingV2Stub + extends io.grpc.stub.AbstractBlockingStub { + private LeetcodeAuthServiceBlockingV2Stub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected LeetcodeAuthServiceBlockingV2Stub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LeetcodeAuthServiceBlockingV2Stub(channel, callOptions); + } + + /** + *
+     * may return NOT_FOUND until the first refresh succeeds.
+     * 
+ */ + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse getToken(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getGetTokenMethod(), getCallOptions(), request); + } + + /** + *
+     * Starts a refresh in the background and returns immediately. Calls made
+     * while a refresh is running are ignored. The stored credentials keep being
+     * served until a refresh succeeds.
+     * 
+ */ + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse refreshToken(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getRefreshTokenMethod(), getCallOptions(), request); + } + } + + /** + * A stub to allow clients to do limited synchronous rpc calls to service LeetcodeAuthService. + */ + public static final class LeetcodeAuthServiceBlockingStub + extends io.grpc.stub.AbstractBlockingStub { + private LeetcodeAuthServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected LeetcodeAuthServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LeetcodeAuthServiceBlockingStub(channel, callOptions); + } + + /** + *
+     * may return NOT_FOUND until the first refresh succeeds.
+     * 
+ */ + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse getToken(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetTokenMethod(), getCallOptions(), request); + } + + /** + *
+     * Starts a refresh in the background and returns immediately. Calls made
+     * while a refresh is running are ignored. The stored credentials keep being
+     * served until a refresh succeeds.
+     * 
+ */ + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse refreshToken(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getRefreshTokenMethod(), getCallOptions(), request); + } + } + + /** + * A stub to allow clients to do ListenableFuture-style rpc calls to service LeetcodeAuthService. + */ + public static final class LeetcodeAuthServiceFutureStub + extends io.grpc.stub.AbstractFutureStub { + private LeetcodeAuthServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected LeetcodeAuthServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LeetcodeAuthServiceFutureStub(channel, callOptions); + } + + /** + *
+     * may return NOT_FOUND until the first refresh succeeds.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture getToken( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetTokenMethod(), getCallOptions()), request); + } + + /** + *
+     * Starts a refresh in the background and returns immediately. Calls made
+     * while a refresh is running are ignored. The stored credentials keep being
+     * served until a refresh succeeds.
+     * 
+ */ + public com.google.common.util.concurrent.ListenableFuture refreshToken( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getRefreshTokenMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_GET_TOKEN = 0; + private static final int METHODID_REFRESH_TOKEN = 1; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final AsyncService serviceImpl; + private final int methodId; + + MethodHandlers(AsyncService serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_GET_TOKEN: + serviceImpl.getToken((org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_REFRESH_TOKEN: + serviceImpl.refreshToken((org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getGetTokenMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest, + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse>( + service, METHODID_GET_TOKEN))) + .addMethod( + getRefreshTokenMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest, + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse>( + service, METHODID_REFRESH_TOKEN))) + .build(); + } + + private static abstract class LeetcodeAuthServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + LeetcodeAuthServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("LeetcodeAuthService"); + } + } + + private static final class LeetcodeAuthServiceFileDescriptorSupplier + extends LeetcodeAuthServiceBaseDescriptorSupplier { + LeetcodeAuthServiceFileDescriptorSupplier() {} + } + + private static final class LeetcodeAuthServiceMethodDescriptorSupplier + extends LeetcodeAuthServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final java.lang.String methodName; + + LeetcodeAuthServiceMethodDescriptorSupplier(java.lang.String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (LeetcodeAuthServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new LeetcodeAuthServiceFileDescriptorSupplier()) + .addMethod(getGetTokenMethod()) + .addMethod(getRefreshTokenMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenRequest.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenRequest.java new file mode 100644 index 000000000..5028fd5c9 --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenRequest.java @@ -0,0 +1,361 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: v1/leetcode_auth.proto +// Protobuf Java Version: 4.36.2 + +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +/** + * Protobuf type {@code leetcodeauth.RefreshTokenRequest} + */ +@com.google.protobuf.Generated +public final class RefreshTokenRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:leetcodeauth.RefreshTokenRequest) + RefreshTokenRequestOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 36, + /* patch= */ 2, + /* suffix= */ "", + "RefreshTokenRequest"); + } + // Use RefreshTokenRequest.newBuilder() to construct. + private RefreshTokenRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private RefreshTokenRequest() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenRequest_descriptor; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.class, org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.Builder.class); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getUnknownFields().writeTo(output); + } + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest)) { + return super.equals(obj); + } + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest other = (org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest) obj; + + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code leetcodeauth.RefreshTokenRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:leetcodeauth.RefreshTokenRequest) + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.class, org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.Builder.class); + } + + // Construct using org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenRequest_descriptor; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest getDefaultInstanceForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.getDefaultInstance(); + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest build() { + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest buildPartial() { + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest result = new org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest(this); + onBuilt(); + return result; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest) { + return mergeFrom((org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest other) { + if (other == org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest.getDefaultInstance()) return this; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + java.util.Objects.requireNonNull(extensionRegistry); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + // @@protoc_insertion_point(builder_scope:leetcodeauth.RefreshTokenRequest) + } + + // @@protoc_insertion_point(class_scope:leetcodeauth.RefreshTokenRequest) + private static final org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest(); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public RefreshTokenRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenRequestOrBuilder.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenRequestOrBuilder.java new file mode 100644 index 000000000..0effe3be9 --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenRequestOrBuilder.java @@ -0,0 +1,12 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: v1/leetcode_auth.proto +// Protobuf Java Version: 4.36.2 + +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +@com.google.protobuf.Generated +public interface RefreshTokenRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:leetcodeauth.RefreshTokenRequest) + com.google.protobuf.MessageOrBuilder { +} diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenResponse.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenResponse.java new file mode 100644 index 000000000..41aba0c19 --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenResponse.java @@ -0,0 +1,456 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: v1/leetcode_auth.proto +// Protobuf Java Version: 4.36.2 + +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +/** + * Protobuf type {@code leetcodeauth.RefreshTokenResponse} + */ +@com.google.protobuf.Generated +public final class RefreshTokenResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:leetcodeauth.RefreshTokenResponse) + RefreshTokenResponseOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 36, + /* patch= */ 2, + /* suffix= */ "", + "RefreshTokenResponse"); + } + // Use RefreshTokenResponse.newBuilder() to construct. + private RefreshTokenResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private RefreshTokenResponse() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenResponse_descriptor; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.class, org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.Builder.class); + } + + public static final int STARTED_FIELD_NUMBER = 1; + private boolean started_ = false; + /** + *
+   * false when a refresh was already running and this call was ignored
+   * 
+ * + * bool started = 1; + * @return The started. + */ + @java.lang.Override + public boolean getStarted() { + return started_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (started_ != false) { + output.writeBool(1, started_); + } + getUnknownFields().writeTo(output); + } + private int computeSerializedSize_0() { + int size = 0; + if (started_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(1, started_); + } + return size; + } + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + size += computeSerializedSize_0(); + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse)) { + return super.equals(obj); + } + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse other = (org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse) obj; + + if (getStarted() + != other.getStarted()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + STARTED_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getStarted()); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code leetcodeauth.RefreshTokenResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:leetcodeauth.RefreshTokenResponse) + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.class, org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.Builder.class); + } + + // Construct using org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + started_ = false; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuth.internal_static_leetcodeauth_RefreshTokenResponse_descriptor; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse getDefaultInstanceForType() { + return org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.getDefaultInstance(); + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse build() { + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse buildPartial() { + org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse result = new org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.started_ = started_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse) { + return mergeFrom((org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse other) { + if (other == org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse.getDefaultInstance()) return this; + if (other.getStarted() != false) { + setStarted(other.getStarted()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + java.util.Objects.requireNonNull(extensionRegistry); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + started_ = input.readBool(); + bitField0_ |= 0x00000001; + break; + } // case 8 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private boolean started_ ; + /** + *
+     * false when a refresh was already running and this call was ignored
+     * 
+ * + * bool started = 1; + * @return The started. + */ + @java.lang.Override + public boolean getStarted() { + return started_; + } + /** + *
+     * false when a refresh was already running and this call was ignored
+     * 
+ * + * bool started = 1; + * @param value The started to set. + * @return This builder for chaining. + */ + public Builder setStarted(boolean value) { + + started_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * false when a refresh was already running and this call was ignored
+     * 
+ * + * bool started = 1; + * @return This builder for chaining. + */ + public Builder clearStarted() { + bitField0_ = (bitField0_ & ~0x00000001); + started_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:leetcodeauth.RefreshTokenResponse) + } + + // @@protoc_insertion_point(class_scope:leetcodeauth.RefreshTokenResponse) + private static final org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse(); + } + + public static org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public RefreshTokenResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenResponseOrBuilder.java b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenResponseOrBuilder.java new file mode 100644 index 000000000..08d1034a4 --- /dev/null +++ b/lib/leetcode-auth-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcodeauth/v1/RefreshTokenResponseOrBuilder.java @@ -0,0 +1,22 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: v1/leetcode_auth.proto +// Protobuf Java Version: 4.36.2 + +package org.patinanetwork.codebloom.grpc.leetcodeauth.v1; + +@com.google.protobuf.Generated +public interface RefreshTokenResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:leetcodeauth.RefreshTokenResponse) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * false when a refresh was already running and this call was ignored
+   * 
+ * + * bool started = 1; + * @return The started. + */ + boolean getStarted(); +} diff --git a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateRequestOrBuilder.java b/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateRequestOrBuilder.java deleted file mode 100644 index 3dacf6ebc..000000000 --- a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateRequestOrBuilder.java +++ /dev/null @@ -1,36 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: LeetcodeAuthStealerService.proto -// Protobuf Java Version: 4.36.2 - -package org.patinanetwork.codebloom.grpc.leetcode.auth.v1; - -@com.google.protobuf.Generated -public interface AuthenticateRequestOrBuilder extends - // @@protoc_insertion_point(interface_extends:codebloom.leetcode.auth.v1.AuthenticateRequest) - com.google.protobuf.MessageOrBuilder { - - /** - * string login = 1; - * @return The login. - */ - java.lang.String getLogin(); - /** - * string login = 1; - * @return The bytes for login. - */ - com.google.protobuf.ByteString - getLoginBytes(); - - /** - * string password = 2; - * @return The password. - */ - java.lang.String getPassword(); - /** - * string password = 2; - * @return The bytes for password. - */ - com.google.protobuf.ByteString - getPasswordBytes(); -} diff --git a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateResponse.java b/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateResponse.java deleted file mode 100644 index cf72223cd..000000000 --- a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateResponse.java +++ /dev/null @@ -1,645 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: LeetcodeAuthStealerService.proto -// Protobuf Java Version: 4.36.2 - -package org.patinanetwork.codebloom.grpc.leetcode.auth.v1; - -/** - * Protobuf type {@code codebloom.leetcode.auth.v1.AuthenticateResponse} - */ -@com.google.protobuf.Generated -public final class AuthenticateResponse extends - com.google.protobuf.GeneratedMessage implements - // @@protoc_insertion_point(message_implements:codebloom.leetcode.auth.v1.AuthenticateResponse) - AuthenticateResponseOrBuilder { -private static final long serialVersionUID = 0L; - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 36, - /* patch= */ 2, - /* suffix= */ "", - "AuthenticateResponse"); - } - // Use AuthenticateResponse.newBuilder() to construct. - private AuthenticateResponse(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - } - private AuthenticateResponse() { - leetcodeSession_ = ""; - csrfToken_ = ""; - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_descriptor; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.class, org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.Builder.class); - } - - public static final int LEETCODE_SESSION_FIELD_NUMBER = 1; - @SuppressWarnings("serial") - private volatile java.lang.Object leetcodeSession_ = ""; - /** - * string leetcode_session = 1; - * @return The leetcodeSession. - */ - @java.lang.Override - public java.lang.String getLeetcodeSession() { - java.lang.Object ref = leetcodeSession_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - leetcodeSession_ = s; - return s; - } - } - /** - * string leetcode_session = 1; - * @return The bytes for leetcodeSession. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getLeetcodeSessionBytes() { - java.lang.Object ref = leetcodeSession_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - leetcodeSession_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int CSRF_TOKEN_FIELD_NUMBER = 2; - @SuppressWarnings("serial") - private volatile java.lang.Object csrfToken_ = ""; - /** - * string csrf_token = 2; - * @return The csrfToken. - */ - @java.lang.Override - public java.lang.String getCsrfToken() { - java.lang.Object ref = csrfToken_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - csrfToken_ = s; - return s; - } - } - /** - * string csrf_token = 2; - * @return The bytes for csrfToken. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getCsrfTokenBytes() { - java.lang.Object ref = csrfToken_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - csrfToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - private byte memoizedIsInitialized = -1; - @java.lang.Override - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - memoizedIsInitialized = 1; - return true; - } - - @java.lang.Override - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(leetcodeSession_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 1, leetcodeSession_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(csrfToken_)) { - com.google.protobuf.GeneratedMessage.writeString(output, 2, csrfToken_); - } - getUnknownFields().writeTo(output); - } - private int computeSerializedSize_0() { - int size = 0; - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(leetcodeSession_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(1, leetcodeSession_); - } - if (!com.google.protobuf.GeneratedMessage.isStringEmpty(csrfToken_)) { - size += com.google.protobuf.GeneratedMessage.computeStringSize(2, csrfToken_); - } - return size; - } - @java.lang.Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - size += computeSerializedSize_0(); - size += getUnknownFields().getSerializedSize(); - memoizedSize = size; - return size; - } - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse)) { - return super.equals(obj); - } - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse other = (org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse) obj; - - if (!getLeetcodeSession() - .equals(other.getLeetcodeSession())) return false; - if (!getCsrfToken() - .equals(other.getCsrfToken())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; - return true; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + LEETCODE_SESSION_FIELD_NUMBER; - hash = (53 * hash) + getLeetcodeSession().hashCode(); - hash = (37 * hash) + CSRF_TOKEN_FIELD_NUMBER; - hash = (53 * hash) + getCsrfToken().hashCode(); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input); - } - - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input); - } - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessage - .parseWithIOException(PARSER, input, extensionRegistry); - } - - @java.lang.Override - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - public static Builder newBuilder(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - @java.lang.Override - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code codebloom.leetcode.auth.v1.AuthenticateResponse} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements - // @@protoc_insertion_point(builder_implements:codebloom.leetcode.auth.v1.AuthenticateResponse) - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponseOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_descriptor; - } - - @java.lang.Override - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.class, org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.Builder.class); - } - - // Construct using org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.newBuilder() - private Builder() { - - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - - } - @java.lang.Override - public Builder clear() { - super.clear(); - bitField0_ = 0; - leetcodeSession_ = ""; - csrfToken_ = ""; - return this; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_descriptor; - } - - @java.lang.Override - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse getDefaultInstanceForType() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.getDefaultInstance(); - } - - @java.lang.Override - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse build() { - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - @java.lang.Override - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse buildPartial() { - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse result = new org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse(this); - if (bitField0_ != 0) { buildPartial0(result); } - onBuilt(); - return result; - } - - private void buildPartial0(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse result) { - int from_bitField0_ = bitField0_; - if (((from_bitField0_ & 0x00000001) != 0)) { - result.leetcodeSession_ = leetcodeSession_; - } - if (((from_bitField0_ & 0x00000002) != 0)) { - result.csrfToken_ = csrfToken_; - } - } - - @java.lang.Override - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse) { - return mergeFrom((org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse other) { - if (other == org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.getDefaultInstance()) return this; - if (!other.getLeetcodeSession().isEmpty()) { - leetcodeSession_ = other.leetcodeSession_; - bitField0_ |= 0x00000001; - onChanged(); - } - if (!other.getCsrfToken().isEmpty()) { - csrfToken_ = other.csrfToken_; - bitField0_ |= 0x00000002; - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - onChanged(); - return this; - } - - @java.lang.Override - public final boolean isInitialized() { - return true; - } - - @java.lang.Override - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - java.util.Objects.requireNonNull(extensionRegistry); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - case 10: { - leetcodeSession_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000001; - break; - } // case 10 - case 18: { - csrfToken_ = input.readStringRequireUtf8(); - bitField0_ |= 0x00000002; - break; - } // case 18 - default: { - if (!super.parseUnknownField(input, extensionRegistry, tag)) { - done = true; // was an endgroup tag - } - break; - } // default: - } // switch (tag) - } // while (!done) - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.unwrapIOException(); - } finally { - onChanged(); - } // finally - return this; - } - private int bitField0_; - - private java.lang.Object leetcodeSession_ = ""; - /** - * string leetcode_session = 1; - * @return The leetcodeSession. - */ - public java.lang.String getLeetcodeSession() { - java.lang.Object ref = leetcodeSession_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - leetcodeSession_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * string leetcode_session = 1; - * @return The bytes for leetcodeSession. - */ - public com.google.protobuf.ByteString - getLeetcodeSessionBytes() { - java.lang.Object ref = leetcodeSession_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - leetcodeSession_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string leetcode_session = 1; - * @param value The leetcodeSession to set. - * @return This builder for chaining. - */ - public Builder setLeetcodeSession( - java.lang.String value) { - java.util.Objects.requireNonNull(value); - leetcodeSession_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - /** - * string leetcode_session = 1; - * @return This builder for chaining. - */ - public Builder clearLeetcodeSession() { - leetcodeSession_ = getDefaultInstance().getLeetcodeSession(); - bitField0_ = (bitField0_ & ~0x00000001); - onChanged(); - return this; - } - /** - * string leetcode_session = 1; - * @param value The bytes for leetcodeSession to set. - * @return This builder for chaining. - */ - public Builder setLeetcodeSessionBytes( - com.google.protobuf.ByteString value) { - java.util.Objects.requireNonNull(value); - checkByteStringIsUtf8(value); - leetcodeSession_ = value; - bitField0_ |= 0x00000001; - onChanged(); - return this; - } - - private java.lang.Object csrfToken_ = ""; - /** - * string csrf_token = 2; - * @return The csrfToken. - */ - public java.lang.String getCsrfToken() { - java.lang.Object ref = csrfToken_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - csrfToken_ = s; - return s; - } else { - return (java.lang.String) ref; - } - } - /** - * string csrf_token = 2; - * @return The bytes for csrfToken. - */ - public com.google.protobuf.ByteString - getCsrfTokenBytes() { - java.lang.Object ref = csrfToken_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - csrfToken_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - /** - * string csrf_token = 2; - * @param value The csrfToken to set. - * @return This builder for chaining. - */ - public Builder setCsrfToken( - java.lang.String value) { - java.util.Objects.requireNonNull(value); - csrfToken_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - /** - * string csrf_token = 2; - * @return This builder for chaining. - */ - public Builder clearCsrfToken() { - csrfToken_ = getDefaultInstance().getCsrfToken(); - bitField0_ = (bitField0_ & ~0x00000002); - onChanged(); - return this; - } - /** - * string csrf_token = 2; - * @param value The bytes for csrfToken to set. - * @return This builder for chaining. - */ - public Builder setCsrfTokenBytes( - com.google.protobuf.ByteString value) { - java.util.Objects.requireNonNull(value); - checkByteStringIsUtf8(value); - csrfToken_ = value; - bitField0_ |= 0x00000002; - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:codebloom.leetcode.auth.v1.AuthenticateResponse) - } - - // @@protoc_insertion_point(class_scope:codebloom.leetcode.auth.v1.AuthenticateResponse) - private static final org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse DEFAULT_INSTANCE; - static { - DEFAULT_INSTANCE = new org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse(); - } - - public static org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - @java.lang.Override - public AuthenticateResponse parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (com.google.protobuf.UninitializedMessageException e) { - throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException(e) - .setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - @java.lang.Override - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - -} - diff --git a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateResponseOrBuilder.java b/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateResponseOrBuilder.java deleted file mode 100644 index 3fec30fce..000000000 --- a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/AuthenticateResponseOrBuilder.java +++ /dev/null @@ -1,36 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: LeetcodeAuthStealerService.proto -// Protobuf Java Version: 4.36.2 - -package org.patinanetwork.codebloom.grpc.leetcode.auth.v1; - -@com.google.protobuf.Generated -public interface AuthenticateResponseOrBuilder extends - // @@protoc_insertion_point(interface_extends:codebloom.leetcode.auth.v1.AuthenticateResponse) - com.google.protobuf.MessageOrBuilder { - - /** - * string leetcode_session = 1; - * @return The leetcodeSession. - */ - java.lang.String getLeetcodeSession(); - /** - * string leetcode_session = 1; - * @return The bytes for leetcodeSession. - */ - com.google.protobuf.ByteString - getLeetcodeSessionBytes(); - - /** - * string csrf_token = 2; - * @return The csrfToken. - */ - java.lang.String getCsrfToken(); - /** - * string csrf_token = 2; - * @return The bytes for csrfToken. - */ - com.google.protobuf.ByteString - getCsrfTokenBytes(); -} diff --git a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/LeetcodeAuthStealerServiceGrpc.java b/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/LeetcodeAuthStealerServiceGrpc.java deleted file mode 100644 index 2013a8363..000000000 --- a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/LeetcodeAuthStealerServiceGrpc.java +++ /dev/null @@ -1,329 +0,0 @@ -package org.patinanetwork.codebloom.grpc.leetcode.auth.v1; - -import static io.grpc.MethodDescriptor.generateFullMethodName; - -/** - */ -@io.grpc.stub.annotations.GrpcGenerated -public final class LeetcodeAuthStealerServiceGrpc { - - private LeetcodeAuthStealerServiceGrpc() {} - - public static final java.lang.String SERVICE_NAME = "codebloom.leetcode.auth.v1.LeetcodeAuthStealerService"; - - // Static method descriptors that strictly reflect the proto. - private static volatile io.grpc.MethodDescriptor getAuthenticateMethod; - - @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "Authenticate", - requestType = org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.class, - responseType = org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.class, - methodType = io.grpc.MethodDescriptor.MethodType.UNARY) - public static io.grpc.MethodDescriptor getAuthenticateMethod() { - io.grpc.MethodDescriptor getAuthenticateMethod; - if ((getAuthenticateMethod = LeetcodeAuthStealerServiceGrpc.getAuthenticateMethod) == null) { - synchronized (LeetcodeAuthStealerServiceGrpc.class) { - if ((getAuthenticateMethod = LeetcodeAuthStealerServiceGrpc.getAuthenticateMethod) == null) { - LeetcodeAuthStealerServiceGrpc.getAuthenticateMethod = getAuthenticateMethod = - io.grpc.MethodDescriptor.newBuilder() - .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "Authenticate")) - .setSampledToLocalTracing(true) - .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest.getDefaultInstance())) - .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse.getDefaultInstance())) - .setSchemaDescriptor(new LeetcodeAuthStealerServiceMethodDescriptorSupplier("Authenticate")) - .build(); - } - } - } - return getAuthenticateMethod; - } - - /** - * Creates a new async stub that supports all call types for the service - */ - public static LeetcodeAuthStealerServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LeetcodeAuthStealerServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LeetcodeAuthStealerServiceStub(channel, callOptions); - } - }; - return LeetcodeAuthStealerServiceStub.newStub(factory, channel); - } - - /** - * Creates a new blocking-style stub that supports all types of calls on the service - */ - public static LeetcodeAuthStealerServiceBlockingV2Stub newBlockingV2Stub( - io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LeetcodeAuthStealerServiceBlockingV2Stub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LeetcodeAuthStealerServiceBlockingV2Stub(channel, callOptions); - } - }; - return LeetcodeAuthStealerServiceBlockingV2Stub.newStub(factory, channel); - } - - /** - * Creates a new blocking-style stub that supports unary and streaming output calls on the service - */ - public static LeetcodeAuthStealerServiceBlockingStub newBlockingStub( - io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LeetcodeAuthStealerServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LeetcodeAuthStealerServiceBlockingStub(channel, callOptions); - } - }; - return LeetcodeAuthStealerServiceBlockingStub.newStub(factory, channel); - } - - /** - * Creates a new ListenableFuture-style stub that supports unary calls on the service - */ - public static LeetcodeAuthStealerServiceFutureStub newFutureStub( - io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LeetcodeAuthStealerServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LeetcodeAuthStealerServiceFutureStub(channel, callOptions); - } - }; - return LeetcodeAuthStealerServiceFutureStub.newStub(factory, channel); - } - - /** - */ - public interface AsyncService { - - /** - */ - default void authenticate(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getAuthenticateMethod(), responseObserver); - } - } - - /** - * Base class for the server implementation of the service LeetcodeAuthStealerService. - */ - public static abstract class LeetcodeAuthStealerServiceImplBase - implements io.grpc.BindableService, AsyncService { - - @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { - return LeetcodeAuthStealerServiceGrpc.bindService(this); - } - } - - /** - * A stub to allow clients to do asynchronous rpc calls to service LeetcodeAuthStealerService. - */ - public static final class LeetcodeAuthStealerServiceStub - extends io.grpc.stub.AbstractAsyncStub { - private LeetcodeAuthStealerServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @java.lang.Override - protected LeetcodeAuthStealerServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LeetcodeAuthStealerServiceStub(channel, callOptions); - } - - /** - */ - public void authenticate(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest request, - io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getAuthenticateMethod(), getCallOptions()), request, responseObserver); - } - } - - /** - * A stub to allow clients to do synchronous rpc calls to service LeetcodeAuthStealerService. - */ - public static final class LeetcodeAuthStealerServiceBlockingV2Stub - extends io.grpc.stub.AbstractBlockingStub { - private LeetcodeAuthStealerServiceBlockingV2Stub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @java.lang.Override - protected LeetcodeAuthStealerServiceBlockingV2Stub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LeetcodeAuthStealerServiceBlockingV2Stub(channel, callOptions); - } - - /** - */ - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse authenticate(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest request) throws io.grpc.StatusException { - return io.grpc.stub.ClientCalls.blockingV2UnaryCall( - getChannel(), getAuthenticateMethod(), getCallOptions(), request); - } - } - - /** - * A stub to allow clients to do limited synchronous rpc calls to service LeetcodeAuthStealerService. - */ - public static final class LeetcodeAuthStealerServiceBlockingStub - extends io.grpc.stub.AbstractBlockingStub { - private LeetcodeAuthStealerServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @java.lang.Override - protected LeetcodeAuthStealerServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LeetcodeAuthStealerServiceBlockingStub(channel, callOptions); - } - - /** - */ - public org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse authenticate(org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest request) { - return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getAuthenticateMethod(), getCallOptions(), request); - } - } - - /** - * A stub to allow clients to do ListenableFuture-style rpc calls to service LeetcodeAuthStealerService. - */ - public static final class LeetcodeAuthStealerServiceFutureStub - extends io.grpc.stub.AbstractFutureStub { - private LeetcodeAuthStealerServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - super(channel, callOptions); - } - - @java.lang.Override - protected LeetcodeAuthStealerServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LeetcodeAuthStealerServiceFutureStub(channel, callOptions); - } - - /** - */ - public com.google.common.util.concurrent.ListenableFuture authenticate( - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest request) { - return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getAuthenticateMethod(), getCallOptions()), request); - } - } - - private static final int METHODID_AUTHENTICATE = 0; - - private static final class MethodHandlers implements - io.grpc.stub.ServerCalls.UnaryMethod, - io.grpc.stub.ServerCalls.ServerStreamingMethod, - io.grpc.stub.ServerCalls.ClientStreamingMethod, - io.grpc.stub.ServerCalls.BidiStreamingMethod { - private final AsyncService serviceImpl; - private final int methodId; - - MethodHandlers(AsyncService serviceImpl, int methodId) { - this.serviceImpl = serviceImpl; - this.methodId = methodId; - } - - @java.lang.Override - @java.lang.SuppressWarnings("unchecked") - public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - case METHODID_AUTHENTICATE: - serviceImpl.authenticate((org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; - default: - throw new AssertionError(); - } - } - - @java.lang.Override - @java.lang.SuppressWarnings("unchecked") - public io.grpc.stub.StreamObserver invoke( - io.grpc.stub.StreamObserver responseObserver) { - switch (methodId) { - default: - throw new AssertionError(); - } - } - } - - public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { - return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) - .addMethod( - getAuthenticateMethod(), - io.grpc.stub.ServerCalls.asyncUnaryCall( - new MethodHandlers< - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest, - org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse>( - service, METHODID_AUTHENTICATE))) - .build(); - } - - private static abstract class LeetcodeAuthStealerServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { - LeetcodeAuthStealerServiceBaseDescriptorSupplier() {} - - @java.lang.Override - public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { - return org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceOuterClass.getDescriptor(); - } - - @java.lang.Override - public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { - return getFileDescriptor().findServiceByName("LeetcodeAuthStealerService"); - } - } - - private static final class LeetcodeAuthStealerServiceFileDescriptorSupplier - extends LeetcodeAuthStealerServiceBaseDescriptorSupplier { - LeetcodeAuthStealerServiceFileDescriptorSupplier() {} - } - - private static final class LeetcodeAuthStealerServiceMethodDescriptorSupplier - extends LeetcodeAuthStealerServiceBaseDescriptorSupplier - implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { - private final java.lang.String methodName; - - LeetcodeAuthStealerServiceMethodDescriptorSupplier(java.lang.String methodName) { - this.methodName = methodName; - } - - @java.lang.Override - public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { - return getServiceDescriptor().findMethodByName(methodName); - } - } - - private static volatile io.grpc.ServiceDescriptor serviceDescriptor; - - public static io.grpc.ServiceDescriptor getServiceDescriptor() { - io.grpc.ServiceDescriptor result = serviceDescriptor; - if (result == null) { - synchronized (LeetcodeAuthStealerServiceGrpc.class) { - result = serviceDescriptor; - if (result == null) { - serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) - .setSchemaDescriptor(new LeetcodeAuthStealerServiceFileDescriptorSupplier()) - .addMethod(getAuthenticateMethod()) - .build(); - } - } - } - return result; - } -} diff --git a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/LeetcodeAuthStealerServiceOuterClass.java b/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/LeetcodeAuthStealerServiceOuterClass.java deleted file mode 100644 index e56ef60d7..000000000 --- a/lib/leetcode-auth-stealer-service/src/main/java/org/patinanetwork/codebloom/grpc/leetcode/auth/v1/LeetcodeAuthStealerServiceOuterClass.java +++ /dev/null @@ -1,79 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: LeetcodeAuthStealerService.proto -// Protobuf Java Version: 4.36.2 - -package org.patinanetwork.codebloom.grpc.leetcode.auth.v1; - -@com.google.protobuf.Generated -public final class LeetcodeAuthStealerServiceOuterClass extends com.google.protobuf.GeneratedFile { - private LeetcodeAuthStealerServiceOuterClass() {} - static { - com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( - com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, - /* major= */ 4, - /* minor= */ 36, - /* patch= */ 2, - /* suffix= */ "", - "LeetcodeAuthStealerServiceOuterClass"); - } - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistryLite registry) { - } - - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistry registry) { - registerAllExtensions( - (com.google.protobuf.ExtensionRegistryLite) registry); - } - static final com.google.protobuf.Descriptors.Descriptor - internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_fieldAccessorTable; - static final com.google.protobuf.Descriptors.Descriptor - internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_descriptor; - static final - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_fieldAccessorTable; - - public static com.google.protobuf.Descriptors.FileDescriptor - getDescriptor() { - return descriptor; - } - private static final com.google.protobuf.Descriptors.FileDescriptor - descriptor; - static { - java.lang.String[] descriptorData = { - "\n LeetcodeAuthStealerService.proto\022\032code" + - "bloom.leetcode.auth.v1\"6\n\023AuthenticateRe" + - "quest\022\r\n\005login\030\001 \001(\t\022\020\n\010password\030\002 \001(\t\"D" + - "\n\024AuthenticateResponse\022\030\n\020leetcode_sessi" + - "on\030\001 \001(\t\022\022\n\ncsrf_token\030\002 \001(\t2\217\001\n\032Leetcod" + - "eAuthStealerService\022q\n\014Authenticate\022/.co" + - "debloom.leetcode.auth.v1.AuthenticateReq" + - "uest\0320.codebloom.leetcode.auth.v1.Authen" + - "ticateResponseB5\n1org.patinanetwork.code" + - "bloom.grpc.leetcode.auth.v1P\001b\006proto3" - }; - descriptor = com.google.protobuf.Descriptors.FileDescriptor - .internalBuildGeneratedFileFrom(descriptorData, - new com.google.protobuf.Descriptors.FileDescriptor[] { - }); - internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_descriptor = - getDescriptor().getMessageType(0); - internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_codebloom_leetcode_auth_v1_AuthenticateRequest_descriptor, - new java.lang.String[] { "Login", "Password", }); - internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_descriptor = - getDescriptor().getMessageType(1); - internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_codebloom_leetcode_auth_v1_AuthenticateResponse_descriptor, - new java.lang.String[] { "LeetcodeSession", "CsrfToken", }); - descriptor.resolveAllFeaturesImmutable(); - } - - // @@protoc_insertion_point(outer_class_scope) -} diff --git a/mvnw b/mvnw index 41c0f0c23..1ddd97b9e 100755 --- a/mvnw +++ b/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Required ENV vars: # ------------------ @@ -27,284 +27,312 @@ # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 # MAVEN_SKIP_RC - flag to disable loading of mavenrc files # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then +if [ -z "$MAVEN_SKIP_RC" ]; then - if [ -f /etc/mavenrc ] ; then + if [ -f /usr/local/etc/mavenrc ]; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ]; then . /etc/mavenrc fi - if [ -f "$HOME/.mavenrc" ] ; then + if [ -f "$HOME/.mavenrc" ]; then . "$HOME/.mavenrc" fi fi # OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; +cygwin=false +darwin=false mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi +case "$(uname)" in +CYGWIN*) cygwin=true ;; +MINGW*) mingw=true ;; +Darwin*) + darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)" + export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home" + export JAVA_HOME fi - ;; + fi + ;; esac -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` +if [ -z "$JAVA_HOME" ]; then + if [ -r /etc/gentoo-release ]; then + JAVA_HOME=$(java-config --jre-home) fi fi -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - # For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +if $cygwin; then + [ -n "$JAVA_HOME" ] \ + && JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] \ + && CLASSPATH=$(cygpath --path --unix "$CLASSPATH") fi # For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +if $mingw; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] \ + && JAVA_HOME="$( + cd "$JAVA_HOME" || ( + echo "cannot cd into $JAVA_HOME." >&2 + exit 1 + ) + pwd + )" fi if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin; then + javaHome="$(dirname "$javaExecutable")" + javaExecutable="$(cd "$javaHome" && pwd -P)/javac" else - javaExecutable="`readlink -f \"$javaExecutable\"`" + javaExecutable="$(readlink -f "$javaExecutable")" fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` + javaHome="$(dirname "$javaExecutable")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') JAVA_HOME="$javaHome" export JAVA_HOME fi fi fi -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then +if [ -z "$JAVACMD" ]; then + if [ -n "$JAVA_HOME" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`which java`" + JAVACMD="$( + \unset -f command 2>/dev/null + \command -v java + )" fi fi -if [ ! -x "$JAVACMD" ] ; then +if [ ! -x "$JAVACMD" ]; then echo "Error: JAVA_HOME is not defined correctly." >&2 echo " We cannot execute $JAVACMD" >&2 exit 1 fi -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." +if [ -z "$JAVA_HOME" ]; then + echo "Warning: JAVA_HOME environment variable is not set." >&2 fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" + if [ -z "$1" ]; then + echo "Path not specified to find_maven_basedir" >&2 return 1 fi basedir="$1" wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then + while [ "$wdir" != '/' ]; do + if [ -d "$wdir"/.mvn ]; then basedir=$wdir break fi # workaround for JBEAP-8937 (on Solaris 10/Sparc) if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + wdir=$( + cd "$wdir/.." || exit 1 + pwd + ) fi # end of workaround done - echo "${basedir}" + printf '%s' "$( + cd "$basedir" || exit 1 + pwd + )" } # concatenates all lines of a file concat_lines() { if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' <"$1" fi } -BASE_DIR=`find_maven_basedir "$(pwd)"` +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") if [ -z "$BASE_DIR" ]; then - exit 1; + exit 1 fi +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + ########################################################################################## # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central # This allows using the maven wrapper in projects that prohibit checking in binary data. ########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar" + fi + while IFS="=" read -r key value; do + case "$key" in wrapperUrl) + wrapperUrl=$(trim "${value-}") + break + ;; + esac + done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget >/dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget ${QUIET:+"$QUIET"} "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + wget ${QUIET:+"$QUIET"} --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" + elif command -v curl >/dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl ${QUIET:+"$QUIET"} -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl ${QUIET:+"$QUIET"} --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi fi + fi fi ########################################################################################## # End of extension ########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in wrapperSha256Sum) + wrapperSha256Sum=$(trim "${value-}") + break + ;; + esac +done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum >/dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c - >/dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi fi + MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` + [ -n "$JAVA_HOME" ] \ + && JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] \ + && CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] \ + && MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") fi # Provide a "standardized" way to retrieve the CLI args that will # work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" export MAVEN_CMD_LINE_ARGS WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +# shellcheck disable=SC2086 # safe args exec "$JAVACMD" \ $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 86115719e..c453424c6 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,182 +1,206 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.4 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. >&2 +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. >&2 +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. >&2 +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. >&2 +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index dcc657e7c..82fac982c 100644 --- a/pom.xml +++ b/pom.xml @@ -235,7 +235,28 @@ true + + + kr.motd.maven + os-maven-plugin + 1.7.1 + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + + ${project.basedir}/internal/leetcode-auth-service/proto + com.google.protobuf:protoc:4.36.2:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:1.84.1:exe:${os.detected.classifier} + ${project.basedir}/lib/leetcode-auth-service/src/main/java + false + + org.codehaus.mojo build-helper-maven-plugin @@ -249,7 +270,7 @@ - lib/leetcode-auth-stealer-service/src/main/java + lib/leetcode-auth-service/src/main/java diff --git a/src/main/java/org/patinanetwork/codebloom/api/admin/AdminController.java b/src/main/java/org/patinanetwork/codebloom/api/admin/AdminController.java index 796ea1154..d58d47831 100644 --- a/src/main/java/org/patinanetwork/codebloom/api/admin/AdminController.java +++ b/src/main/java/org/patinanetwork/codebloom/api/admin/AdminController.java @@ -32,10 +32,10 @@ import org.patinanetwork.codebloom.common.dto.autogen.UnsafeGenericFailureResponse; import org.patinanetwork.codebloom.common.dto.question.QuestionWithUserDto; import org.patinanetwork.codebloom.common.dto.user.UserDto; +import org.patinanetwork.codebloom.common.leetcode.auth.LeetcodeAuthenticationService; import org.patinanetwork.codebloom.common.security.AuthenticationObject; import org.patinanetwork.codebloom.common.security.annotation.Protected; import org.patinanetwork.codebloom.common.time.StandardizedOffsetDateTime; -import org.patinanetwork.codebloom.scheduled.auth.LeetcodeAuthStealer; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -54,7 +54,7 @@ public class AdminController { private final DiscordClubManager discordClubManager; private final LeaderboardManager leaderboardManager; private final DiscordClubRepository discordClubRepository; - private final LeetcodeAuthStealer leetcodeAuthStealer; + private final LeetcodeAuthenticationService leetcodeAuthenticationService; private final IncompleteQuestionRequeuer incompleteQuestionRequeuer; public AdminController( @@ -65,7 +65,7 @@ public AdminController( final DiscordClubManager discordClubManager, final LeaderboardManager leaderboardManager, final DiscordClubRepository discordClubRepository, - final LeetcodeAuthStealer leetcodeAuthStealer, + final LeetcodeAuthenticationService leetcodeAuthenticationService, final IncompleteQuestionRequeuer incompleteQuestionRequeuer) { this.leaderboardRepository = leaderboardRepository; this.userRepository = userRepository; @@ -74,7 +74,7 @@ public AdminController( this.discordClubManager = discordClubManager; this.leaderboardManager = leaderboardManager; this.discordClubRepository = discordClubRepository; - this.leetcodeAuthStealer = leetcodeAuthStealer; + this.leetcodeAuthenticationService = leetcodeAuthenticationService; this.incompleteQuestionRequeuer = incompleteQuestionRequeuer; } @@ -351,7 +351,7 @@ public ResponseEntity> sendDiscordAnnouncement( @PostMapping("/leetcode/token") public ResponseEntity> refreshLeetcodeToken( @Protected(admin = true) final AuthenticationObject authenticationObject) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); return ResponseEntity.ok(ApiResponder.success("LeetCode token refresh triggered.", Empty.of())); } diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientImpl.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientImpl.java index db125de88..e9e3b0d2e 100644 --- a/src/main/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientImpl.java +++ b/src/main/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientImpl.java @@ -24,6 +24,7 @@ import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.patinanetwork.codebloom.common.db.models.question.QuestionDifficulty; +import org.patinanetwork.codebloom.common.leetcode.auth.LeetcodeAuthenticationService; import org.patinanetwork.codebloom.common.leetcode.models.Lang; import org.patinanetwork.codebloom.common.leetcode.models.LeetcodeDetailedQuestion; import org.patinanetwork.codebloom.common.leetcode.models.LeetcodeQuestion; @@ -38,7 +39,6 @@ import org.patinanetwork.codebloom.common.leetcode.queries.GetUserProfile; import org.patinanetwork.codebloom.common.leetcode.queries.SelectAcceptedSubmisisonsQuery; import org.patinanetwork.codebloom.common.leetcode.queries.SelectProblemQuery; -import org.patinanetwork.codebloom.scheduled.auth.LeetcodeAuthStealer; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; @@ -51,6 +51,7 @@ public class LeetcodeClientImpl implements LeetcodeClient { private static final String GRAPHQL_ENDPOINT = "https://leetcode.com/graphql"; private static final String ERROR_COUNT_METRIC_NAME = "leetcode.client.exception"; + private static final String EMPTY_COOKIE = ""; private final ObjectMapper mapper; @@ -59,14 +60,15 @@ public class LeetcodeClientImpl implements LeetcodeClient { @VisibleForTesting HttpClient client; - private final LeetcodeAuthStealer leetcodeAuthStealer; + private final LeetcodeAuthenticationService leetcodeAuthenticationService; - public LeetcodeClientImpl(final MeterRegistry meterRegistry, final LeetcodeAuthStealer leetcodeAuthStealer) { + public LeetcodeClientImpl( + final MeterRegistry meterRegistry, final LeetcodeAuthenticationService leetcodeAuthenticationService) { this.meterRegistry = meterRegistry; this.client = HttpClient.newHttpClient(); this.mapper = new ObjectMapper(); - this.leetcodeAuthStealer = leetcodeAuthStealer; + this.leetcodeAuthenticationService = leetcodeAuthenticationService; } private Counter errorCounter() { @@ -86,16 +88,19 @@ private Counter errorCounter() { private String buildCookieHeader() { List cookies = new ArrayList<>(); + var authCreds = leetcodeAuthenticationService.getAuthenticationCredentials(); - String session = leetcodeAuthStealer.getCookie(); - cookies.add("LEETCODE_SESSION=" + session); + var session = authCreds.token(); + session.ifPresent(s -> { + cookies.add("LEETCODE_SESSION=" + s); + }); - String csrf = leetcodeAuthStealer.getCsrf(); - if (csrf != null) { - cookies.add("csrftoken=" + csrf); - } + var csrf = authCreds.csrf(); + csrf.ifPresent(c -> { + cookies.add("csrftoken=" + c); + }); - return String.join("; ", cookies); + return cookies.isEmpty() ? EMPTY_COOKIE : String.join("; ", cookies); } /** @@ -152,7 +157,7 @@ public LeetcodeQuestion findQuestionBySlug(final String slug) { if (statusCode != 200) { if (isThrottled(statusCode)) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); } throw new LeetcodeClientException("API Returned status " + statusCode + ": " + body); } @@ -244,7 +249,7 @@ public ArrayList findSubmissionsByUsername(final String user if (statusCode != 200) { if (isThrottled(statusCode)) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); } throw new LeetcodeClientException("API Returned status " + statusCode + ": " + body); } @@ -304,7 +309,7 @@ public LeetcodeDetailedQuestion findSubmissionDetailBySubmissionId(final long su if (statusCode != 200) { if (isThrottled(statusCode)) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); } throw new LeetcodeClientException("API Returned status " + statusCode + ": " + body); } @@ -318,7 +323,7 @@ public LeetcodeDetailedQuestion findSubmissionDetailBySubmissionId(final long su long memory = baseNode.path("memory").asLong(); String memoryDisplay = baseNode.path("memoryDisplay").asText(); float memoryPercentile = (float) baseNode.path("memoryPercentile").asDouble(); - String code = baseNode.path("code").asText(); + String code = baseNode.path("code").asText(null); String langName = baseNode.path("lang").path("name").asText(); String langVerboseName = baseNode.path("lang").path("verboseName").asText(); Lang lang = (Strings.isNullOrEmpty(langName) || Strings.isNullOrEmpty(langVerboseName)) @@ -327,7 +332,7 @@ public LeetcodeDetailedQuestion findSubmissionDetailBySubmissionId(final long su // if any of these are empty, then extremely likely that we're throttled. if (Strings.isNullOrEmpty(runtimeDisplay) || Strings.isNullOrEmpty(memoryDisplay)) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); } LeetcodeDetailedQuestion question = new LeetcodeDetailedQuestion( @@ -366,7 +371,7 @@ public POTD getPotd() { if (statusCode != 200) { if (isThrottled(statusCode)) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); } throw new LeetcodeClientException("API Returned status " + statusCode + ": " + body); } @@ -413,7 +418,7 @@ public UserProfile getUserProfile(final String username) { if (statusCode != 200) { if (isThrottled(statusCode)) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); } throw new LeetcodeClientException("API Returned status " + statusCode + ": " + body); } @@ -453,7 +458,7 @@ public Set getAllTopicTags() { if (statusCode != 200) { if (isThrottled(statusCode)) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); } throw new LeetcodeClientException( "Non-successful response getting topics from Leetcode API. Status code: " + statusCode); @@ -501,7 +506,7 @@ public List getAllProblems() { String body = response.body(); if (statusCode != 200) { if (isThrottled(statusCode)) { - leetcodeAuthStealer.reloadCookie(); + leetcodeAuthenticationService.refresh(); } throw new LeetcodeClientException( "Non-successful response getting all questions from Leetcode API. Status code: " + statusCode); diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/AuthenticationCredentials.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/AuthenticationCredentials.java index 21b5fdc18..3d30f5329 100644 --- a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/AuthenticationCredentials.java +++ b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/AuthenticationCredentials.java @@ -1,3 +1,5 @@ package org.patinanetwork.codebloom.common.leetcode.auth; -public record AuthenticationCredentials(String token, String csrf) {} +import java.util.Optional; + +public record AuthenticationCredentials(Optional token, Optional csrf) {} diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/CiLeetcodeAuthenticationService.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/CiLeetcodeAuthenticationService.java new file mode 100644 index 000000000..7c8597356 --- /dev/null +++ b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/CiLeetcodeAuthenticationService.java @@ -0,0 +1,18 @@ +package org.patinanetwork.codebloom.common.leetcode.auth; + +import java.util.Optional; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +@Service +@Profile("ci") +public class CiLeetcodeAuthenticationService implements LeetcodeAuthenticationService { + + @Override + public AuthenticationCredentials getAuthenticationCredentials() { + return new AuthenticationCredentials(Optional.empty(), Optional.empty()); + } + + @Override + public void refresh() {} +} diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DefaultLeetcodeAuthenticationService.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DefaultLeetcodeAuthenticationService.java new file mode 100644 index 000000000..d8095ef80 --- /dev/null +++ b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DefaultLeetcodeAuthenticationService.java @@ -0,0 +1,39 @@ +package org.patinanetwork.codebloom.common.leetcode.auth; + +import java.util.Optional; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuthServiceGrpc.LeetcodeAuthServiceBlockingStub; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +@AllArgsConstructor +@Profile("!ci") +public class DefaultLeetcodeAuthenticationService implements LeetcodeAuthenticationService { + + private final LeetcodeAuthServiceBlockingStub leetcodeAuthGrpcService; + + public AuthenticationCredentials getAuthenticationCredentials() { + try { + + var tokenResponse = leetcodeAuthGrpcService.getToken( + GetTokenRequest.newBuilder().build()); + + return new AuthenticationCredentials( + Optional.ofNullable(tokenResponse.getToken()), Optional.ofNullable(tokenResponse.getCsrf())); + } catch (Exception e) { + log.error("LeetcodeAuthenticationService.getAuthenticationCredentials failed", e); + return new AuthenticationCredentials(Optional.empty(), Optional.empty()); + } + } + + @Async + public void refresh() { + leetcodeAuthGrpcService.refreshToken(RefreshTokenRequest.newBuilder().build()); + } +} diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClient.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClient.java deleted file mode 100644 index e2c183c9a..000000000 --- a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClient.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.patinanetwork.codebloom.common.leetcode.auth; - -import java.util.Optional; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest; -import org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceGrpc.LeetcodeAuthStealerServiceBlockingStub; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; - -@Component -@Primary -@EnableConfigurationProperties(DirectLeetcodeAuthenticationClientProperties.class) -@ConditionalOnProperty(name = "leetcode.auth.strategy", havingValue = "direct") -@AllArgsConstructor -@Slf4j -public class DirectLeetcodeAuthenticationClient implements LeetcodeAuthenticationClient { - private final LeetcodeAuthStealerServiceBlockingStub lassService; - private final DirectLeetcodeAuthenticationClientProperties properties; - - @Override - public Optional getLeetcodeCookie() { - try { - return Optional.of(lassService.authenticate(AuthenticateRequest.newBuilder() - .setLogin(properties.username()) - .setPassword(properties.password()) - .build())) - .map(r -> new AuthenticationCredentials(r.getLeetcodeSession(), r.getCsrfToken())); - } catch (Exception e) { - log.error("failed to get leetcode cookie from LASS service", e); - return Optional.empty(); - } - } -} diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClientProperties.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClientProperties.java deleted file mode 100644 index 8dcf3a776..000000000 --- a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClientProperties.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.patinanetwork.codebloom.common.leetcode.auth; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("leetcode.auth.direct") -@ConditionalOnProperty(name = "leetcode.auth.strategy", havingValue = "direct") -public record DirectLeetcodeAuthenticationClientProperties(String username, String password) {} diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClient.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClient.java deleted file mode 100644 index 94824be55..000000000 --- a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClient.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.patinanetwork.codebloom.common.leetcode.auth; - -import java.util.Optional; -import lombok.AllArgsConstructor; -import org.patinanetwork.codebloom.playwright.PlaywrightClient; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.stereotype.Component; - -@Component -@EnableConfigurationProperties(GitHubLeetcodeAuthenticationClientProperties.class) -@ConditionalOnProperty(name = "leetcode.auth.strategy", havingValue = "github") -@AllArgsConstructor -public class GitHubLeetcodeAuthenticationClient implements LeetcodeAuthenticationClient { - private final PlaywrightClient playwrightClient; - private final GitHubLeetcodeAuthenticationClientProperties properties; - - @Override - public Optional getLeetcodeCookie() { - return playwrightClient - .getLeetcodeCookie(properties.username(), properties.password()) - .map(a -> - new AuthenticationCredentials(a.getToken(), a.getCsrf().orElse(null))); - } -} diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClientProperties.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClientProperties.java deleted file mode 100644 index 424ca8ea5..000000000 --- a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClientProperties.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.patinanetwork.codebloom.common.leetcode.auth; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("leetcode.auth.github") -@ConditionalOnProperty(name = "leetcode.auth.strategy", havingValue = "github") -public record GitHubLeetcodeAuthenticationClientProperties(String username, String password) {} diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/LeetcodeAuthenticationClient.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/LeetcodeAuthenticationClient.java deleted file mode 100644 index 890bf939e..000000000 --- a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/LeetcodeAuthenticationClient.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.patinanetwork.codebloom.common.leetcode.auth; - -import java.util.Optional; - -public interface LeetcodeAuthenticationClient { - Optional getLeetcodeCookie(); -} diff --git a/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/LeetcodeAuthenticationService.java b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/LeetcodeAuthenticationService.java new file mode 100644 index 000000000..626ab4fa3 --- /dev/null +++ b/src/main/java/org/patinanetwork/codebloom/common/leetcode/auth/LeetcodeAuthenticationService.java @@ -0,0 +1,8 @@ +package org.patinanetwork.codebloom.common.leetcode.auth; + +public interface LeetcodeAuthenticationService { + + AuthenticationCredentials getAuthenticationCredentials(); + + void refresh(); +} diff --git a/src/main/java/org/patinanetwork/codebloom/config/GrpcClientConfiguration.java b/src/main/java/org/patinanetwork/codebloom/config/GrpcClientConfiguration.java index c87ecf9bd..5be1c7253 100644 --- a/src/main/java/org/patinanetwork/codebloom/config/GrpcClientConfiguration.java +++ b/src/main/java/org/patinanetwork/codebloom/config/GrpcClientConfiguration.java @@ -7,15 +7,15 @@ import io.micrometer.observation.ObservationRegistry; import java.time.Duration; import lombok.AllArgsConstructor; -import org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceGrpc; -import org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceGrpc.LeetcodeAuthStealerServiceBlockingStub; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuthServiceGrpc; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuthServiceGrpc.LeetcodeAuthServiceBlockingStub; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @AllArgsConstructor -@EnableConfigurationProperties(LeetcodeAuthStealerGrpcClientConfiguration.class) +@EnableConfigurationProperties(LeetcodeAuthServiceGrpcClientConfiguration.class) public class GrpcClientConfiguration { private final ObservationRegistry observationRegistry; @@ -41,20 +41,20 @@ private ClientInterceptor[] interceptors( } @Bean - ManagedChannel lassServiceChannel( - LeetcodeAuthStealerGrpcClientConfiguration authStealerProps, + ManagedChannel lasServiceChannel( + LeetcodeAuthServiceGrpcClientConfiguration authProps, GrpcRequestIdInterceptor requestIdInterceptor, ObservationGrpcClientInterceptor observationInterceptor) { - var builder = ManagedChannelBuilder.forTarget(authStealerProps.host()) - .intercept(interceptors(authStealerProps.timeout(), requestIdInterceptor, observationInterceptor)); + var builder = ManagedChannelBuilder.forTarget(authProps.host()) + .intercept(interceptors(authProps.timeout(), requestIdInterceptor, observationInterceptor)); - return (authStealerProps.tls() ? builder.useTransportSecurity() : builder.usePlaintext()).build(); + return (authProps.tls() ? builder.useTransportSecurity() : builder.usePlaintext()).build(); } @Bean - LeetcodeAuthStealerServiceBlockingStub lassServiceBlockingStub(ManagedChannel lassServiceChannel) { + LeetcodeAuthServiceBlockingStub lasServiceBlockingStub(ManagedChannel lasServiceChannel) { - return LeetcodeAuthStealerServiceGrpc.newBlockingStub(lassServiceChannel); + return LeetcodeAuthServiceGrpc.newBlockingStub(lasServiceChannel); } } diff --git a/src/main/java/org/patinanetwork/codebloom/config/LeetcodeAuthStealerGrpcClientConfiguration.java b/src/main/java/org/patinanetwork/codebloom/config/LeetcodeAuthServiceGrpcClientConfiguration.java similarity index 59% rename from src/main/java/org/patinanetwork/codebloom/config/LeetcodeAuthStealerGrpcClientConfiguration.java rename to src/main/java/org/patinanetwork/codebloom/config/LeetcodeAuthServiceGrpcClientConfiguration.java index e1fe7479e..6dbbbfc1a 100644 --- a/src/main/java/org/patinanetwork/codebloom/config/LeetcodeAuthStealerGrpcClientConfiguration.java +++ b/src/main/java/org/patinanetwork/codebloom/config/LeetcodeAuthServiceGrpcClientConfiguration.java @@ -3,5 +3,5 @@ import java.time.Duration; import org.springframework.boot.context.properties.ConfigurationProperties; -@ConfigurationProperties("grpc.leetcode-auth-stealer-service") -public record LeetcodeAuthStealerGrpcClientConfiguration(String host, boolean tls, Duration timeout) {} +@ConfigurationProperties("grpc.leetcode-auth-service") +public record LeetcodeAuthServiceGrpcClientConfiguration(String host, boolean tls, Duration timeout) {} diff --git a/src/main/java/org/patinanetwork/codebloom/playwright/PlaywrightClient.java b/src/main/java/org/patinanetwork/codebloom/playwright/PlaywrightClient.java index 188789b4e..efa680af4 100644 --- a/src/main/java/org/patinanetwork/codebloom/playwright/PlaywrightClient.java +++ b/src/main/java/org/patinanetwork/codebloom/playwright/PlaywrightClient.java @@ -1,21 +1,12 @@ package org.patinanetwork.codebloom.playwright; -import com.microsoft.playwright.ElementHandle; import com.microsoft.playwright.Page; -import com.microsoft.playwright.options.LoadState; import com.microsoft.playwright.options.ScreenshotType; -import java.util.List; -import java.util.Optional; import java.util.function.Function; -import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; -import org.patinanetwork.codebloom.common.db.models.auth.Auth; import org.patinanetwork.codebloom.common.db.models.usertag.Tag; -import org.patinanetwork.codebloom.common.email.EmailClient; -import org.patinanetwork.codebloom.common.email.Message; import org.patinanetwork.codebloom.common.email.client.github.GithubOAuthEmailClient; import org.patinanetwork.codebloom.common.url.ServerUrlUtils; -import org.patinanetwork.codebloom.scheduled.auth.CodeExtractor; import org.springframework.stereotype.Component; @Component @@ -26,7 +17,6 @@ public class PlaywrightClient { "Mozilla/5.0 (Linux; U; Android 4.4.1; SAMSUNG SM-J210G Build/KTU84P) AppleWebKit/536.31 (KHTML, like Gecko) Chrome/48.0.2090.359 Mobile Safari/601.9"; private final ServerUrlUtils serverUrlUtils; - private final EmailClient emailClient; private final PlaywrightProvider playwrightProvider; public PlaywrightClient( @@ -34,7 +24,6 @@ public PlaywrightClient( final GithubOAuthEmailClient githubOAuthEmailClient, final PlaywrightProvider playwrightProvider) { this.serverUrlUtils = serverUrlUtils; - this.emailClient = githubOAuthEmailClient; this.playwrightProvider = playwrightProvider; } @@ -53,94 +42,4 @@ public byte[] getCodebloomLeaderboardScreenshot(final int page, final Tag tag) { return screenshot; }); } - - public Optional getLeetcodeCookie(String githubUsername, String githubPassword) { - return withPage((p) -> { - p.navigate("https://leetcode.com/accounts/github/login/?next=%2F"); - - log.info("Navigated to leetcode.com login"); - - p.waitForLoadState(LoadState.NETWORKIDLE); - - p.fill("#login_field", githubUsername); - p.fill("#password", githubPassword); - - log.info("Filled in credentials, clicking login..."); - - p.click("input[name=\"commit\"]"); - - if (p.isVisible("#device-verification-prompt") || p.isVisible("#session-otp-input-description")) { - log.info("2FA Required"); - List messages; - - p.waitForTimeout(10000); - - try { - messages = emailClient.getPastMessages(); - } catch (Exception e) { - log.info("Failed to retrieve past messages"); - throw new RuntimeException("Failed to retrieve past messages", e); - } - - Message target = null; - for (Message m : messages) { - // Don't break so we can get the newest available code. - if (m.getSubject().equals("[GitHub] Please verify your device")) { - log.info("Found verification email"); - target = m; - } - } - - if (target == null) { - throw new RuntimeException( - "Something went wrong when parsing the inbox. Manual intervention required"); - } - - String code = CodeExtractor.extractCode(target.getMessage()); - - log.info("Found code in email, will fill now..."); - - if (code == null) { - throw new RuntimeException("Code was not found in the email. Manual intervention required."); - } - - p.fill("input[name='otp']", code); - - log.info("Page filled!"); - } - - if (p.isVisible("button[name=\"authorize\"]")) { - List buttons = p.querySelectorAll("button[name=\"authorize\"]"); - if (buttons.size() > 1) { - // Click the second button (which is the actual authorize button) - buttons.get(1).click(); - } - log.info("Authorization button clicked"); - } - - p.waitForURL("https://leetcode.com/"); - - log.info("Back to leetcode.com!"); - - if (p.url().equals("https://leetcode.com/")) { - var cookieMap = p.context().cookies().stream() - .filter(cookie -> cookie.name.equals("LEETCODE_SESSION") || cookie.name.equals("csrftoken")) - .collect(Collectors.toMap(cookie -> cookie.name, cookie -> cookie.value)); - - String sessionToken = cookieMap.get("LEETCODE_SESSION"); - String csrf = cookieMap.get("csrftoken"); - if (sessionToken != null) { - log.info("Cookie found!"); - return Optional.of(Auth.builder() - .token(sessionToken) - .csrf(Optional.ofNullable(csrf)) - .build()); - } - } else { - log.info("Should be authenticated but not authenticated."); - } - - return Optional.empty(); - }); - } } diff --git a/src/main/java/org/patinanetwork/codebloom/scheduled/auth/CodeExtractor.java b/src/main/java/org/patinanetwork/codebloom/scheduled/auth/CodeExtractor.java deleted file mode 100644 index b1d4b9fb1..000000000 --- a/src/main/java/org/patinanetwork/codebloom/scheduled/auth/CodeExtractor.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.patinanetwork.codebloom.scheduled.auth; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class CodeExtractor { - - public static String extractCode(final String content) { - Pattern pattern = Pattern.compile("Verification code:\\s*(\\d{6})"); - Matcher matcher = pattern.matcher(content); - - if (matcher.find()) { - return matcher.group(1); - } - - return null; - } -} diff --git a/src/main/java/org/patinanetwork/codebloom/scheduled/auth/LeetcodeAuthStealer.java b/src/main/java/org/patinanetwork/codebloom/scheduled/auth/LeetcodeAuthStealer.java deleted file mode 100644 index 2baf14c47..000000000 --- a/src/main/java/org/patinanetwork/codebloom/scheduled/auth/LeetcodeAuthStealer.java +++ /dev/null @@ -1,178 +0,0 @@ -package org.patinanetwork.codebloom.scheduled.auth; - -import com.google.common.annotations.VisibleForTesting; -import io.micrometer.core.annotation.Timed; -import java.time.temporal.ChronoUnit; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import lombok.extern.slf4j.Slf4j; -import org.patinanetwork.codebloom.common.db.models.auth.Auth; -import org.patinanetwork.codebloom.common.db.repos.auth.AuthRepository; -import org.patinanetwork.codebloom.common.env.Env; -import org.patinanetwork.codebloom.common.leetcode.auth.AuthenticationCredentials; -import org.patinanetwork.codebloom.common.leetcode.auth.LeetcodeAuthenticationClient; -import org.patinanetwork.codebloom.common.redis.RedisClient; -import org.patinanetwork.codebloom.common.reporter.Reporter; -import org.patinanetwork.codebloom.common.reporter.report.Report; -import org.patinanetwork.codebloom.common.reporter.report.location.Location; -import org.patinanetwork.codebloom.common.time.StandardizedOffsetDateTime; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -@Timed(value = "leetcode.client.execution") -public class LeetcodeAuthStealer { - - @VisibleForTesting - // CHECKSTYLE:OFF - final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(); - // CHECKSTYLE:ON - - private volatile String cookie; - private volatile String csrf; - - /** So we don't report that a csrf token is missing more than once per machine lifecycle. */ - private boolean reported = false; - - private final RedisClient redisClient; - private final AuthRepository authRepository; - private final Reporter reporter; - private final Env env; - private final LeetcodeAuthenticationClient leetcodeAuthenticationClient; - - public LeetcodeAuthStealer( - final RedisClient redisClient, - final AuthRepository authRepository, - final Reporter reporter, - final Env env, - final LeetcodeAuthenticationClient leetcodeAuthenticationClient) { - this.redisClient = redisClient; - this.authRepository = authRepository; - this.reporter = reporter; - this.env = env; - this.leetcodeAuthenticationClient = leetcodeAuthenticationClient; - } - - /** - * DO NOT RETURN THE TOKEN IN ANY API ENDPOINT.
This function utilizes Playwright in order to get an - * authentication key from Leetcode. That code is stored in the database and can then be used to run authenticated - * queries such as being used to retrieve code from our user submissions. - */ - @Scheduled(initialDelay = 0, fixedDelay = 15, timeUnit = TimeUnit.MINUTES) - public void stealAuthCookie() { - boolean acquired = LOCK.writeLock().tryLock(); - if (!acquired) { - log.info("Lock failed to be acquired, bouncing..."); - return; - } - - try { - var mostRecentAuth = authRepository.getMostRecentAuth().filter(auth -> auth.getCreatedAt() - .isAfter(StandardizedOffsetDateTime.now().minus(4, ChronoUnit.HOURS))); - - // The auth token should be refreshed every 4 hours. - if (mostRecentAuth.isPresent()) { - log.info("Auth token already exists, using token from database."); - cookie = mostRecentAuth.get().getToken(); - csrf = mostRecentAuth.get().getCsrf().orElse(null); - return; - } - - log.info("falling back to checking redis client..."); - Optional authToken = redisClient.getAuth(); - - log.info("auth token in redis = {}", authToken.isPresent()); - - if (authToken.isPresent()) { - log.info("auth token found in redis client"); - cookie = authToken.get(); - csrf = null; // don't care in ci. - return; - } - - log.info("auth token not found in redis client"); - log.info("Auth token is missing/expired. Attempting to receive token..."); - - stealCookieImpl(); - } finally { - LOCK.writeLock().unlock(); - } - } - - /** - * There are some cases where leetcode.com may not respect the token anymore. If that is the case, it is best to try - * to steal a new cookie and replace the current one. - * - *

You may await the `CompletableFuture` and receive the brand new token, or call-and-forget. - */ - @Async - public CompletableFuture> reloadCookie() { - boolean acquired = LOCK.writeLock().tryLock(); - if (!acquired) { - log.info("Lock failed to be acquired, bouncing..."); - return CompletableFuture.completedFuture(Optional.empty()); - } - - try { - return CompletableFuture.completedFuture(Optional.ofNullable(stealCookieImpl())); - } finally { - LOCK.writeLock().unlock(); - } - } - - public String getCookie() { - LOCK.readLock().lock(); - try { - return cookie; - } finally { - LOCK.readLock().unlock(); - } - } - - /** - * It's fine if this is null for some requests; it isn't a requirement to fetch data from the GraphQL layer of - * leetcode.com - */ - public String getCsrf() { - if (csrf == null && !reported) { - reported = true; - reporter.log( - "getCsrf", - Report.builder() - .environments(env.getActiveProfiles()) - .location(Location.BACKEND) - .data( - "CSRF token is missing inside of LeetcodeAuthStealer. This may be something to look into.") - .build()); - } - - return csrf; - } - - @VisibleForTesting - String stealCookieImpl() { - Optional auth = leetcodeAuthenticationClient.getLeetcodeCookie(); - if (auth.isPresent()) { - var a = auth.get(); - var csrf = a.csrf(); - var token = a.token(); - - this.csrf = csrf; - this.cookie = token; - redisClient.setAuth(token, 4, ChronoUnit.HOURS); - log.info("auth token stored in redis"); - this.authRepository.createAuth(Auth.builder() - .csrf(Optional.of(csrf)) - .token(token) - .createdAt(StandardizedOffsetDateTime.now()) - .build()); - return cookie; - } - - return null; - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9d0a8dc1c..864a7e935 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -66,10 +66,10 @@ springdoc: version: OPENAPI_3_0 grpc: - leetcode-auth-stealer-service: - host: ${GRPC_LASS_HOST:localhost:50051} - tls: ${GRPC_LASS_TLS:false} - timeout: ${GRPC_LASS_TIMEOUT:2m} # extremely long running, give it time to breathe in local + leetcode-auth-service: + host: ${GRPC_LAS_HOST:localhost:50052} + tls: ${GRPC_LAS_TLS:false} + timeout: ${GRPC_LAS_TIMEOUT:20ms} leetcode: auth: diff --git a/src/test/java/org/patinanetwork/codebloom/api/admin/AdminControllerTest.java b/src/test/java/org/patinanetwork/codebloom/api/admin/AdminControllerTest.java index 3be65b20c..ccba4cb7b 100644 --- a/src/test/java/org/patinanetwork/codebloom/api/admin/AdminControllerTest.java +++ b/src/test/java/org/patinanetwork/codebloom/api/admin/AdminControllerTest.java @@ -30,8 +30,8 @@ import org.patinanetwork.codebloom.common.dto.ApiResponder; import org.patinanetwork.codebloom.common.dto.Empty; import org.patinanetwork.codebloom.common.dto.question.QuestionWithUserDto; +import org.patinanetwork.codebloom.common.leetcode.auth.LeetcodeAuthenticationService; import org.patinanetwork.codebloom.common.time.StandardizedOffsetDateTime; -import org.patinanetwork.codebloom.scheduled.auth.LeetcodeAuthStealer; import org.patinanetwork.codebloom.utilities.exception.ValidationException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -46,7 +46,8 @@ public class AdminControllerTest { private final DiscordClubManager discordClubManager = mock(DiscordClubManager.class); private final LeaderboardManager leaderboardManager = mock(LeaderboardManager.class); private final DiscordClubRepository discordClubRepository = mock(DiscordClubRepository.class); - private final LeetcodeAuthStealer leetcodeAuthStealer = mock(LeetcodeAuthStealer.class); + private final LeetcodeAuthenticationService leetcodeAuthenticationService = + mock(LeetcodeAuthenticationService.class); private final IncompleteQuestionRequeuer incompleteQuestionRequeuer = mock(IncompleteQuestionRequeuer.class); private final AdminController adminController; @@ -60,7 +61,7 @@ public AdminControllerTest() { discordClubManager, leaderboardManager, discordClubRepository, - leetcodeAuthStealer, + leetcodeAuthenticationService, incompleteQuestionRequeuer)); } @@ -73,7 +74,7 @@ void setUp() { questionRepository, discordClubManager, leaderboardManager, - leetcodeAuthStealer, + leetcodeAuthenticationService, incompleteQuestionRequeuer); } @@ -468,7 +469,7 @@ void testRefreshLeetcodeTokenTriggersReload() { assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); assertTrue(response.getBody().isSuccess()); - verify(leetcodeAuthStealer, times(1)).reloadCookie(); + verify(leetcodeAuthenticationService, times(1)).refresh(); } @Test diff --git a/src/test/java/org/patinanetwork/codebloom/common/db/repos/BaseRepositoryTest.java b/src/test/java/org/patinanetwork/codebloom/common/db/repos/BaseRepositoryTest.java index 08325667a..1bd33fe24 100644 --- a/src/test/java/org/patinanetwork/codebloom/common/db/repos/BaseRepositoryTest.java +++ b/src/test/java/org/patinanetwork/codebloom/common/db/repos/BaseRepositoryTest.java @@ -2,9 +2,9 @@ import org.patinanetwork.codebloom.common.email.client.codebloom.OfficialCodebloomEmailClient; import org.patinanetwork.codebloom.common.email.client.github.GithubOAuthEmailClient; +import org.patinanetwork.codebloom.common.leetcode.auth.LeetcodeAuthenticationService; import org.patinanetwork.codebloom.jda.JDAClientManager; import org.patinanetwork.codebloom.jda.command.JDASlashCommandInitializer; -import org.patinanetwork.codebloom.scheduled.auth.LeetcodeAuthStealer; import org.patinanetwork.codebloom.scheduled.submission.SubmissionScheduler; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -31,5 +31,5 @@ public class BaseRepositoryTest { private SubmissionScheduler submissionScheduler; @MockitoBean - private LeetcodeAuthStealer leetcodeAuthStealer; + private LeetcodeAuthenticationService leetcodeAuthenticationService; } diff --git a/src/test/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientCircuitBreakerTest.java b/src/test/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientCircuitBreakerTest.java index 094803b0c..9b83cdd79 100644 --- a/src/test/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientCircuitBreakerTest.java +++ b/src/test/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientCircuitBreakerTest.java @@ -10,9 +10,11 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.patinanetwork.codebloom.scheduled.auth.LeetcodeAuthStealer; +import org.patinanetwork.codebloom.common.leetcode.auth.AuthenticationCredentials; +import org.patinanetwork.codebloom.common.leetcode.auth.LeetcodeAuthenticationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -39,7 +41,7 @@ class LeetcodeClientCircuitBreakerTest { private LeetcodeClientImpl leetcodeClient; @MockitoBean - private LeetcodeAuthStealer leetcodeAuthStealer; + private LeetcodeAuthenticationService leetcodeAuthenticationService; @MockitoBean private HttpClient httpClient; @@ -59,8 +61,8 @@ void setUp() throws Exception { Object target = AopTestUtils.getTargetObject(leetcodeClient); ReflectionTestUtils.setField(target, "client", httpClient); - when(leetcodeAuthStealer.getCookie()).thenReturn("test-cookie"); - when(leetcodeAuthStealer.getCsrf()).thenReturn(null); + when(leetcodeAuthenticationService.getAuthenticationCredentials()) + .thenReturn(new AuthenticationCredentials(Optional.of("test-cookie"), Optional.empty())); when(httpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))) .thenThrow(new RuntimeException("boom")); diff --git a/src/test/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientTest.java b/src/test/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientTest.java index 6f491f35e..b0e44195c 100644 --- a/src/test/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientTest.java +++ b/src/test/java/org/patinanetwork/codebloom/common/leetcode/LeetcodeClientTest.java @@ -12,31 +12,34 @@ import java.net.http.HttpResponse; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.patinanetwork.codebloom.common.db.models.question.QuestionDifficulty; +import org.patinanetwork.codebloom.common.leetcode.auth.AuthenticationCredentials; +import org.patinanetwork.codebloom.common.leetcode.auth.LeetcodeAuthenticationService; import org.patinanetwork.codebloom.common.leetcode.models.LeetcodeDetailedQuestion; import org.patinanetwork.codebloom.common.leetcode.models.LeetcodeQuestion; import org.patinanetwork.codebloom.common.leetcode.models.LeetcodeSubmission; import org.patinanetwork.codebloom.common.leetcode.models.LeetcodeTopicTag; import org.patinanetwork.codebloom.common.leetcode.models.POTD; import org.patinanetwork.codebloom.common.leetcode.models.UserProfile; -import org.patinanetwork.codebloom.scheduled.auth.LeetcodeAuthStealer; public class LeetcodeClientTest { private final MeterRegistry meterRegistry = new SimpleMeterRegistry(); - private final LeetcodeAuthStealer leetcodeAuthStealer = mock(LeetcodeAuthStealer.class); + private final LeetcodeAuthenticationService leetcodeAuthenticationService = + mock(LeetcodeAuthenticationService.class); private final HttpClient httpClient = mock(HttpClient.class); private final HttpResponse httpResponse = mock(HttpResponse.class); private final LeetcodeClientImpl leetcodeClient; public LeetcodeClientTest() throws Exception { - leetcodeClient = new LeetcodeClientImpl(meterRegistry, leetcodeAuthStealer); + leetcodeClient = new LeetcodeClientImpl(meterRegistry, leetcodeAuthenticationService); setupMockHttpClient(leetcodeClient, httpClient); } @@ -46,8 +49,8 @@ void setupMockHttpClient(LeetcodeClientImpl leetcodeClient, HttpClient httpClien @BeforeEach void setup() { - when(leetcodeAuthStealer.getCookie()).thenReturn("test-session-cookie"); - when(leetcodeAuthStealer.getCsrf()).thenReturn(null); + when(leetcodeAuthenticationService.getAuthenticationCredentials()) + .thenReturn(new AuthenticationCredentials(Optional.of("test-session-cookie"), Optional.empty())); } @Test @@ -109,7 +112,7 @@ void testFindQuestionBySlugThrottledAndTriggersReloadCookie(int statusCode) thro fail("Exception expected"); } catch (RuntimeException e) { assertTrue(e.getCause().getMessage().contains(String.valueOf(statusCode))); - verify(leetcodeAuthStealer, times(1)).reloadCookie(); + verify(leetcodeAuthenticationService, times(1)).refresh(); } } @@ -171,7 +174,7 @@ void testFindSubmissionsByUsernameThrottledAndTriggersReloadCookie(int statusCod fail("Exception expected"); } catch (RuntimeException e) { assertTrue(e.getCause().getMessage().contains(String.valueOf(statusCode))); - verify(leetcodeAuthStealer, times(1)).reloadCookie(); + verify(leetcodeAuthenticationService, times(1)).refresh(); } } @@ -295,7 +298,7 @@ void testFindSubmissionDetailBySubmissionIdThrottledAndTriggersReloadCookie(int fail("Exception expected"); } catch (RuntimeException e) { assertTrue(e.getCause().getMessage().contains(String.valueOf(statusCode))); - verify(leetcodeAuthStealer, times(1)).reloadCookie(); + verify(leetcodeAuthenticationService, times(1)).refresh(); } } @@ -348,7 +351,7 @@ void testGetPotdThrottledAndTriggersReloadCookie(int statusCode) throws Exceptio fail("Exception expected"); } catch (RuntimeException e) { assertTrue(e.getCause().getMessage().contains(String.valueOf(statusCode))); - verify(leetcodeAuthStealer, times(1)).reloadCookie(); + verify(leetcodeAuthenticationService, times(1)).refresh(); } } @@ -405,7 +408,7 @@ void testGetUserProfileThrottledAndTriggersReloadCookie(int statusCode) throws E fail("Exception expected"); } catch (RuntimeException e) { assertTrue(e.getCause().getMessage().contains(String.valueOf(statusCode))); - verify(leetcodeAuthStealer, times(1)).reloadCookie(); + verify(leetcodeAuthenticationService, times(1)).refresh(); } } @@ -465,7 +468,7 @@ void testGetAllTopicTagsThrottledAndTriggersReloadCookie(int statusCode) throws fail("Exception expected"); } catch (RuntimeException e) { assertTrue(e.getCause().getMessage().contains(String.valueOf(statusCode))); - verify(leetcodeAuthStealer, times(1)).reloadCookie(); + verify(leetcodeAuthenticationService, times(1)).refresh(); } } @@ -572,7 +575,7 @@ void testGetAllProblemsThrottledAndTriggersReloadCookie(int statusCode) throws E fail("Exception expected"); } catch (RuntimeException e) { assertTrue(e.getCause().getMessage().contains(String.valueOf(statusCode))); - verify(leetcodeAuthStealer, times(1)).reloadCookie(); + verify(leetcodeAuthenticationService, times(1)).refresh(); } } diff --git a/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClientTest.java b/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClientTest.java deleted file mode 100644 index ca5763532..000000000 --- a/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/DirectLeetcodeAuthenticationClientTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.patinanetwork.codebloom.common.leetcode.auth; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.grpc.Status; -import java.util.Optional; -import org.junit.jupiter.api.Test; -import org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateRequest; -import org.patinanetwork.codebloom.grpc.leetcode.auth.v1.AuthenticateResponse; -import org.patinanetwork.codebloom.grpc.leetcode.auth.v1.LeetcodeAuthStealerServiceGrpc.LeetcodeAuthStealerServiceBlockingStub; - -public class DirectLeetcodeAuthenticationClientTest { - - private final LeetcodeAuthStealerServiceBlockingStub lassService = - mock(LeetcodeAuthStealerServiceBlockingStub.class); - private final DirectLeetcodeAuthenticationClient client = new DirectLeetcodeAuthenticationClient( - lassService, new DirectLeetcodeAuthenticationClientProperties("user@example.com", "hunter2")); - - @Test - void mapsSessionAndCsrfFromLassResponse() { - when(lassService.authenticate(any(AuthenticateRequest.class))) - .thenReturn(AuthenticateResponse.newBuilder() - .setLeetcodeSession("session-token") - .setCsrfToken("csrf-token") - .build()); - - Optional result = client.getLeetcodeCookie(); - - assertEquals(Optional.of(new AuthenticationCredentials("session-token", "csrf-token")), result); - verify(lassService) - .authenticate(AuthenticateRequest.newBuilder() - .setLogin("user@example.com") - .setPassword("hunter2") - .build()); - } - - @Test - void returnsEmptyWhenLassCallFails() { - when(lassService.authenticate(any(AuthenticateRequest.class))) - .thenThrow(Status.UNAVAILABLE.asRuntimeException()); - - assertTrue(client.getLeetcodeCookie().isEmpty()); - } -} diff --git a/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClientTest.java b/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClientTest.java deleted file mode 100644 index 30bf8e2c7..000000000 --- a/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/GitHubLeetcodeAuthenticationClientTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.patinanetwork.codebloom.common.leetcode.auth; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.Optional; -import org.junit.jupiter.api.Test; -import org.patinanetwork.codebloom.common.db.models.auth.Auth; -import org.patinanetwork.codebloom.playwright.PlaywrightClient; - -public class GitHubLeetcodeAuthenticationClientTest { - - private final PlaywrightClient playwrightClient = mock(PlaywrightClient.class); - private final GitHubLeetcodeAuthenticationClient client = new GitHubLeetcodeAuthenticationClient( - playwrightClient, new GitHubLeetcodeAuthenticationClientProperties("gh-user", "gh-pass")); - - @Test - void mapsTokenAndCsrfFromPlaywrightAuth() { - when(playwrightClient.getLeetcodeCookie("gh-user", "gh-pass")) - .thenReturn(Optional.of(Auth.builder() - .token("session-token") - .csrf(Optional.of("csrf-token")) - .build())); - - assertEquals( - Optional.of(new AuthenticationCredentials("session-token", "csrf-token")), client.getLeetcodeCookie()); - } - - @Test - void returnsEmptyWhenPlaywrightFindsNoCookie() { - when(playwrightClient.getLeetcodeCookie("gh-user", "gh-pass")).thenReturn(Optional.empty()); - - assertTrue(client.getLeetcodeCookie().isEmpty()); - } -} diff --git a/src/test/java/org/patinanetwork/codebloom/scheduled/auth/LeetcodeAuthStealerTest.java b/src/test/java/org/patinanetwork/codebloom/scheduled/auth/LeetcodeAuthStealerTest.java deleted file mode 100644 index 6eb4c680c..000000000 --- a/src/test/java/org/patinanetwork/codebloom/scheduled/auth/LeetcodeAuthStealerTest.java +++ /dev/null @@ -1,704 +0,0 @@ -package org.patinanetwork.codebloom.scheduled.auth; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.*; - -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; -import java.time.temporal.ChronoUnit; -import java.util.Optional; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Timeout; -import org.patinanetwork.codebloom.common.db.models.auth.Auth; -import org.patinanetwork.codebloom.common.db.repos.auth.AuthRepository; -import org.patinanetwork.codebloom.common.env.Env; -import org.patinanetwork.codebloom.common.lag.FakeLag; -import org.patinanetwork.codebloom.common.leetcode.auth.AuthenticationCredentials; -import org.patinanetwork.codebloom.common.leetcode.auth.LeetcodeAuthenticationClient; -import org.patinanetwork.codebloom.common.redis.RedisClient; -import org.patinanetwork.codebloom.common.reporter.Reporter; -import org.patinanetwork.codebloom.common.time.StandardizedOffsetDateTime; -import org.slf4j.LoggerFactory; - -public class LeetcodeAuthStealerTest { - private LeetcodeAuthStealer leetcodeAuthStealer; - - private RedisClient redisClient; - private AuthRepository authRepository; - private Reporter reporter; - private Env env; - private LeetcodeAuthenticationClient leetcodeAuthenticationClient; - - private ListAppender logWatcher; - - public LeetcodeAuthStealerTest() { - redisClient = mock(RedisClient.class); - authRepository = mock(AuthRepository.class); - reporter = mock(Reporter.class); - env = mock(Env.class); - leetcodeAuthenticationClient = mock(LeetcodeAuthenticationClient.class); - } - - @BeforeEach - void setup() { - leetcodeAuthStealer = - spy(new LeetcodeAuthStealer(redisClient, authRepository, reporter, env, leetcodeAuthenticationClient)); - - logWatcher = new ListAppender<>(); - logWatcher.start(); - ((Logger) LoggerFactory.getLogger(leetcodeAuthStealer.getClass())).addAppender(logWatcher); - - when(env.isCi()).thenReturn(false); - playwrightClientResolvesSlowly(Auth.builder().build()); - } - - @AfterEach - void teardown() { - ((Logger) LoggerFactory.getLogger(leetcodeAuthStealer.getClass())).detachAndStopAllAppenders(); - } - - private void playwrightClientResolvesSlowly(Auth authToReturn) { - when(leetcodeAuthenticationClient.getLeetcodeCookie()).thenAnswer(invocation -> { - FakeLag.sleep(1000); - return Optional.ofNullable(authToReturn); - }); - } - - @Test - @Timeout(10) - @DisplayName( - "Verifies multiple threads can acquire read locks concurrently across the same thread pool - Auth Repository") - void testReadLockConcurrentAccessSameThreadPoolAuthRepo() throws InterruptedException { - Auth mockAuth = Auth.builder() - .token("test-token") - .csrf(Optional.of("test-csrf")) - .createdAt(StandardizedOffsetDateTime.now()) - .build(); - when(authRepository.getMostRecentAuth()).thenReturn(Optional.of(mockAuth)); - - leetcodeAuthStealer.stealAuthCookie(); - - ExecutorService pool = Executors.newFixedThreadPool(5); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(5); - AtomicInteger concurrentReads = new AtomicInteger(0); - AtomicInteger maxConcurrentReads = new AtomicInteger(0); - - for (int i = 0; i < 5; i++) { - pool.submit(() -> { - try { - startLatch.await(); - int current = concurrentReads.incrementAndGet(); - maxConcurrentReads.updateAndGet(max -> Math.max(max, current)); - - String cookie = leetcodeAuthStealer.getCookie(); - assertNotNull(cookie); - assertEquals("test-token", cookie); - - Thread.sleep(100); - concurrentReads.decrementAndGet(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - verify(leetcodeAuthStealer, never()).stealCookieImpl(); - - startLatch.countDown(); - assertTrue(doneLatch.await(5, TimeUnit.SECONDS)); - pool.shutdown(); - - assertTrue(maxConcurrentReads.get() > 1, "Multiple read locks should be acquired concurrently"); - } - - @Test - @Timeout(10) - @DisplayName( - "Verifies multiple threads can acquire read locks concurrently across the same thread pool - New cookie fetched") - void testReadLockConcurrentAccessSameThreadPoolNewCookieFetched() throws InterruptedException { - when(authRepository.getMostRecentAuth()).thenReturn(Optional.empty()); - doReturn("cookie").when(leetcodeAuthStealer).stealCookieImpl(); - doReturn("cookie").when(leetcodeAuthStealer).getCookie(); - - leetcodeAuthStealer.stealAuthCookie(); - - ExecutorService executor = Executors.newFixedThreadPool(5); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(5); - AtomicInteger concurrentReads = new AtomicInteger(0); - AtomicInteger maxConcurrentReads = new AtomicInteger(0); - - for (int i = 0; i < 5; i++) { - executor.submit(() -> { - try { - startLatch.await(); - int current = concurrentReads.incrementAndGet(); - maxConcurrentReads.updateAndGet(max -> Math.max(max, current)); - - String cookie = leetcodeAuthStealer.getCookie(); - assertNotNull(cookie); - assertEquals("test-token", cookie); - - Thread.sleep(100); - concurrentReads.decrementAndGet(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(5, TimeUnit.SECONDS)); - executor.shutdown(); - - assertTrue(maxConcurrentReads.get() > 1, "Multiple read locks should be acquired concurrently"); - } - - @Test - @Timeout(10) - @DisplayName( - "Verifies multiple threads can acquire read locks concurrently across different thread pools - Auth Repository") - void testReadLockConcurrentAccessDifferentThreadPoolsAuthRepository() throws InterruptedException { - Auth mockAuth = Auth.builder() - .token("test-token") - .csrf(Optional.of("test-csrf")) - .createdAt(StandardizedOffsetDateTime.now()) - .build(); - when(authRepository.getMostRecentAuth()).thenReturn(Optional.of(mockAuth)); - - leetcodeAuthStealer.stealAuthCookie(); - - ExecutorService pool1 = Executors.newFixedThreadPool(3); - ExecutorService pool2 = Executors.newFixedThreadPool(3); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(6); - AtomicInteger concurrentReads = new AtomicInteger(0); - AtomicInteger maxConcurrentReads = new AtomicInteger(0); - - for (int i = 0; i < 3; i++) { - pool1.submit(() -> { - try { - startLatch.await(); - int current = concurrentReads.incrementAndGet(); - maxConcurrentReads.updateAndGet(max -> Math.max(max, current)); - - String cookie = leetcodeAuthStealer.getCookie(); - assertNotNull(cookie); - assertEquals("test-token", cookie); - - Thread.sleep(100); - concurrentReads.decrementAndGet(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - for (int i = 0; i < 3; i++) { - pool2.submit(() -> { - try { - startLatch.await(); - int current = concurrentReads.incrementAndGet(); - maxConcurrentReads.updateAndGet(max -> Math.max(max, current)); - - String cookie = leetcodeAuthStealer.getCookie(); - assertNotNull(cookie); - assertEquals("test-token", cookie); - - Thread.sleep(100); - concurrentReads.decrementAndGet(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(5, TimeUnit.SECONDS)); - pool1.shutdown(); - - assertTrue( - maxConcurrentReads.get() > 1, - "Multiple read locks should be acquired concurrently across different thread pools"); - } - - @Test - @Timeout(10) - @DisplayName( - "Verifies multiple threads can acquire read locks concurrently across different thread pools - New cookie fetched") - void testReadLockConcurrentAccessDifferentThreadPoolsFetchedNewCookie() throws InterruptedException { - when(authRepository.getMostRecentAuth()).thenReturn(Optional.empty()); - doReturn("string").when(leetcodeAuthStealer).stealCookieImpl(); - doReturn("string").when(leetcodeAuthStealer).getCookie(); - - leetcodeAuthStealer.stealAuthCookie(); - - ExecutorService pool1 = Executors.newFixedThreadPool(3); - ExecutorService pool2 = Executors.newFixedThreadPool(3); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(6); - AtomicInteger concurrentReads = new AtomicInteger(0); - AtomicInteger maxConcurrentReads = new AtomicInteger(0); - - for (int i = 0; i < 3; i++) { - pool1.submit(() -> { - try { - startLatch.await(); - int current = concurrentReads.incrementAndGet(); - maxConcurrentReads.updateAndGet(max -> Math.max(max, current)); - - String cookie = leetcodeAuthStealer.getCookie(); - assertNotNull(cookie); - assertEquals("test-token", cookie); - - Thread.sleep(100); - concurrentReads.decrementAndGet(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - for (int i = 0; i < 3; i++) { - pool2.submit(() -> { - try { - startLatch.await(); - int current = concurrentReads.incrementAndGet(); - maxConcurrentReads.updateAndGet(max -> Math.max(max, current)); - - String cookie = leetcodeAuthStealer.getCookie(); - assertNotNull(cookie); - assertEquals("test-token", cookie); - - Thread.sleep(100); - concurrentReads.decrementAndGet(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(5, TimeUnit.SECONDS)); - pool1.shutdown(); - - assertTrue( - maxConcurrentReads.get() > 1, - "Multiple read locks should be acquired concurrently across different thread pools"); - } - - @Test - @Timeout(15) - @DisplayName("Verifies that only one thread can try to steal cookie at a time across the same thread pool") - void testWriteLockExclusiveAccessSameThreadPool() throws InterruptedException { - when(authRepository.getMostRecentAuth()).thenReturn(Optional.empty()); - - ExecutorService pool = Executors.newFixedThreadPool(3); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(3); - AtomicBoolean isOneWriteBlockingOtherWrites = new AtomicBoolean(false); - - pool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(100); - leetcodeAuthStealer.stealAuthCookie(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - - for (int i = 0; i < 3; i++) { - pool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(200); - - if (!leetcodeAuthStealer.LOCK.writeLock().tryLock()) { - isOneWriteBlockingOtherWrites.set(true); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(10, TimeUnit.SECONDS)); - pool.shutdown(); - - assertTrue( - isOneWriteBlockingOtherWrites.get(), - "Write locks should be exclusive within the same thread pool - only one at a time"); - } - - @Test - @Timeout(15) - @DisplayName("Verifies that only one thread can try to steal cookie at a time across different thread pools") - void testWriteLockExclusiveAccessDifferentThreadPools() throws InterruptedException { - when(authRepository.getMostRecentAuth()).thenReturn(Optional.empty()); - - ExecutorService pool1 = Executors.newFixedThreadPool(2); - ExecutorService pool2 = Executors.newFixedThreadPool(2); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(3); - AtomicBoolean isOneWriteBlockingOtherWrites = new AtomicBoolean(false); - - pool1.submit(() -> { - try { - startLatch.await(); - Thread.sleep(100); - leetcodeAuthStealer.stealAuthCookie(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - - for (int i = 0; i < 3; i++) { - pool2.submit(() -> { - try { - startLatch.await(); - Thread.sleep(200); - - if (!leetcodeAuthStealer.LOCK.writeLock().tryLock()) { - isOneWriteBlockingOtherWrites.set(true); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(10, TimeUnit.SECONDS)); - pool1.shutdown(); - pool2.shutdown(); - - assertTrue( - isOneWriteBlockingOtherWrites.get(), - "Write locks should be exclusive across different thread pools - only one at a time"); - } - - @Test - @Timeout(10) - @DisplayName( - "Verifies that no read operations can happen when stealing authentication cookie in the same thread pool") - void testReadWriteLockInteractionSameThreadPool() throws InterruptedException { - when(authRepository.getMostRecentAuth()).thenReturn(Optional.empty()); - - ExecutorService pool = Executors.newFixedThreadPool(4); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(4); - AtomicBoolean readBlockedByWrite = new AtomicBoolean(false); - - pool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(100); - leetcodeAuthStealer.stealAuthCookie(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - - for (int i = 0; i < 3; i++) { - pool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(200); - - if (!leetcodeAuthStealer.LOCK.readLock().tryLock()) { - readBlockedByWrite.set(true); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(8, TimeUnit.SECONDS)); - pool.shutdown(); - - assertTrue(readBlockedByWrite.get(), "Read operations should be blocked when write lock is held"); - } - - @Test - @Timeout(10) - @DisplayName( - "Verifies that no read operations can happen when stealing authentication cookie in different thread pools") - void testReadWriteLockInteractionDifferentThreadPools() throws InterruptedException { - when(authRepository.getMostRecentAuth()).thenReturn(Optional.empty()); - - ExecutorService writePool = Executors.newFixedThreadPool(1); - ExecutorService readPool = Executors.newFixedThreadPool(3); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(4); - AtomicBoolean readBlockedByWrite = new AtomicBoolean(false); - - writePool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(100); - leetcodeAuthStealer.stealAuthCookie(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - - for (int i = 0; i < 3; i++) { - readPool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(200); - - if (!leetcodeAuthStealer.LOCK.readLock().tryLock()) { - readBlockedByWrite.set(true); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(8, TimeUnit.SECONDS)); - writePool.shutdown(); - readPool.shutdown(); - - assertTrue( - readBlockedByWrite.get(), - "Read operations from different thread pool should wait for write lock to be released"); - } - - @Test - @Timeout(10) - @DisplayName( - "Verifies that no read operations can happen when reloading authentication cookie in the same thread pool") - void testReloadCookieReadWriteLockInteractionSameThreadPool() throws InterruptedException { - ExecutorService pool = Executors.newFixedThreadPool(4); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(4); - AtomicBoolean readBlockedByWrite = new AtomicBoolean(false); - - pool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(100); - leetcodeAuthStealer.reloadCookie(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - - for (int i = 0; i < 3; i++) { - pool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(200); - - if (!leetcodeAuthStealer.LOCK.readLock().tryLock()) { - readBlockedByWrite.set(true); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(8, TimeUnit.SECONDS)); - pool.shutdown(); - - assertTrue(readBlockedByWrite.get(), "Read operations should be blocked when write lock is held"); - } - - @Test - @Timeout(10) - @DisplayName( - "Verifies that no read operations can happen when reloading authentication cookie in different thread pools") - void testReloadCookieReadWriteLockInteractionDifferentThreadPools() throws InterruptedException { - ExecutorService writePool = Executors.newFixedThreadPool(1); - ExecutorService readPool = Executors.newFixedThreadPool(3); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch doneLatch = new CountDownLatch(4); - AtomicBoolean readBlockedByWrite = new AtomicBoolean(false); - - writePool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(100); - leetcodeAuthStealer.reloadCookie(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - - for (int i = 0; i < 3; i++) { - readPool.submit(() -> { - try { - startLatch.await(); - Thread.sleep(200); - - if (!leetcodeAuthStealer.LOCK.readLock().tryLock()) { - readBlockedByWrite.set(true); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - doneLatch.countDown(); - } - }); - } - - startLatch.countDown(); - assertTrue(doneLatch.await(8, TimeUnit.SECONDS)); - writePool.shutdown(); - readPool.shutdown(); - - assertTrue( - readBlockedByWrite.get(), - "Read operations from different thread pool should wait for write lock to be released"); - } - - @Test - @Timeout(10) - @DisplayName("reloadCookie - If one thread is stealing cookie, other thread will bounce") - void testReloadCookieIfOneThreadIsStealingCookieOtherThreadWillBounce() throws InterruptedException { - ExecutorService writePool = Executors.newFixedThreadPool(2); - CountDownLatch latch = new CountDownLatch(1); - - writePool.execute(() -> { - leetcodeAuthStealer.reloadCookie(); - }); - - AtomicReference> ref = new AtomicReference<>(); - writePool.execute(() -> { - try { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - ref.set(leetcodeAuthStealer.reloadCookie().join()); - } finally { - latch.countDown(); - } - }); - - latch.await(2, TimeUnit.SECONDS); - - assertTrue(ref.get().isEmpty()); - } - - @Test - @Timeout(10) - @DisplayName("stealAuthCookie - If one thread is stealing cookie, other thread will bounce") - void testStealAuthCookieIfOneThreadIsStealingCookieOtherThreadWillBounce() throws InterruptedException { - ExecutorService writePool = Executors.newFixedThreadPool(2); - CountDownLatch latch = new CountDownLatch(1); - - writePool.execute(() -> { - leetcodeAuthStealer.stealAuthCookie(); - }); - - writePool.execute(() -> { - try { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - leetcodeAuthStealer.stealAuthCookie(); - } finally { - latch.countDown(); - } - }); - - latch.await(2, TimeUnit.SECONDS); - - assertTrue(logWatcher.list.stream() - .anyMatch(log -> log.getLevel().equals(Level.INFO) - && log.getFormattedMessage().contains("Lock failed to be acquired, bouncing..."))); - } - - @Test - @DisplayName("stealCookieImpl - Stores fetched credentials in memory, redis, and the auth repository") - void testStealCookieImplPersistsCredentials() { - when(leetcodeAuthenticationClient.getLeetcodeCookie()) - .thenReturn(Optional.of(new AuthenticationCredentials("new-token", "new-csrf"))); - - assertEquals("new-token", leetcodeAuthStealer.stealCookieImpl()); - - assertEquals("new-token", leetcodeAuthStealer.getCookie()); - assertEquals("new-csrf", leetcodeAuthStealer.getCsrf()); - verify(redisClient).setAuth("new-token", 4, ChronoUnit.HOURS); - verify(authRepository) - .createAuth(argThat(a -> "new-token".equals(a.getToken()) - && Optional.of("new-csrf").equals(a.getCsrf()))); - } - - @Test - @DisplayName("stealCookieImpl - Persists nothing when no credentials are returned") - void testStealCookieImplWithoutCredentials() { - when(leetcodeAuthenticationClient.getLeetcodeCookie()).thenReturn(Optional.empty()); - - assertNull(leetcodeAuthStealer.stealCookieImpl()); - - verify(redisClient, never()).setAuth(anyString(), anyLong(), any()); - verify(authRepository, never()).createAuth(any()); - } -} From 6dade03ec91b6c65d44ef3ef753e9a8637724634 Mon Sep 17 00:00:00 2001 From: Tahmid Ahmed Date: Thu, 5 Nov 2026 00:39:34 -0500 Subject: [PATCH 2/3] DINO-1164: pr fixes --- src/main/resources/application.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 864a7e935..5dd1aa054 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -69,7 +69,8 @@ grpc: leetcode-auth-service: host: ${GRPC_LAS_HOST:localhost:50052} tls: ${GRPC_LAS_TLS:false} - timeout: ${GRPC_LAS_TIMEOUT:20ms} + # both RPCs answer from Redis in milliseconds; refreshToken returns before the login runs + timeout: ${GRPC_LAS_TIMEOUT:1s} leetcode: auth: From f8d02a72d135ee2f9efe323e2880ebfdda99207e Mon Sep 17 00:00:00 2001 From: Tahmid Ahmed Date: Thu, 5 Nov 2026 14:37:28 -0500 Subject: [PATCH 3/3] DINO-1164: pr fixes --- ...aultLeetcodeAuthenticationServiceTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/DefaultLeetcodeAuthenticationServiceTest.java diff --git a/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/DefaultLeetcodeAuthenticationServiceTest.java b/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/DefaultLeetcodeAuthenticationServiceTest.java new file mode 100644 index 000000000..7e89fd155 --- /dev/null +++ b/src/test/java/org/patinanetwork/codebloom/common/leetcode/auth/DefaultLeetcodeAuthenticationServiceTest.java @@ -0,0 +1,53 @@ +package org.patinanetwork.codebloom.common.leetcode.auth; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.grpc.Status; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenRequest; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.GetTokenResponse; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.LeetcodeAuthServiceGrpc.LeetcodeAuthServiceBlockingStub; +import org.patinanetwork.codebloom.grpc.leetcodeauth.v1.RefreshTokenRequest; + +class DefaultLeetcodeAuthenticationServiceTest { + + private final LeetcodeAuthServiceBlockingStub stub = mock(LeetcodeAuthServiceBlockingStub.class); + private final DefaultLeetcodeAuthenticationService service = new DefaultLeetcodeAuthenticationService(stub); + + @Test + void returnsStoredCredentials() { + when(stub.getToken(any(GetTokenRequest.class))) + .thenReturn(GetTokenResponse.newBuilder() + .setToken("session") + .setCsrf("csrf") + .build()); + + AuthenticationCredentials credentials = service.getAuthenticationCredentials(); + + assertEquals(Optional.of("session"), credentials.token()); + assertEquals(Optional.of("csrf"), credentials.csrf()); + } + + @Test + void returnsEmptyCredentialsWhenAuthServiceFails() { + when(stub.getToken(any(GetTokenRequest.class))).thenThrow(Status.NOT_FOUND.asRuntimeException()); + + AuthenticationCredentials credentials = service.getAuthenticationCredentials(); + + assertTrue(credentials.token().isEmpty()); + assertTrue(credentials.csrf().isEmpty()); + } + + @Test + void refreshRequestsTokenRefresh() { + service.refresh(); + + verify(stub).refreshToken(any(RefreshTokenRequest.class)); + } +}