Skip to content

Commit

Permalink
Update API Token Integration
Browse files Browse the repository at this point in the history
  • Loading branch information
TFyre committed Jan 7, 2025
1 parent 412503a commit 5412a62
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 78 deletions.
66 changes: 53 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,30 +186,70 @@ bambu.printers.myprinter1.stream.watch-dog=5m

### Cloud Section

Enable MQTT connection via cloud instead of directly to printer. You can either provide the username/password or a access token.
Enable MQTT connection via cloud instead of directly to printer.

* Option 1 - username/password
The access userid and token can be fetched from your browser cookies or a multi liner curl
```bash
export [email protected]
export MY_PASSWORD=fixme

# Request verification code
curl -sS --fail -X POST -H 'Content-Type: application/json' -d "{\"account\":\"${MY_USERNAME}\",\"password\":\"${MY_PASSWORD}\"}" https://api.bambulab.com/v1/user-service/user/login | jq
```

Output:
```json
{
"accessToken": "",
"refreshToken": "",
"expiresIn": 0,
"refreshExpiresIn": 0,
"tfaKey": "",
"accessMethod": "",
"loginType": "verifyCode"
}
```

Provide the username and password for https://bambulab.com/ in the format below
```bash
# Check email for verification code
export MY_CODE=1234
curl -sS --fail -X POST -H 'Content-Type: application/json' -d "{\"account\":\"${MY_USERNAME}\",\"code\":\"${MY_CODE}\"}" https://api.bambulab.com/v1/user-service/user/login | jq
```

* Option 2 - access token
Output:
```json
{
"accessToken": "AA...",
"refreshToken": "SAME_AS_ACCESS_TOKEN",
"expiresIn": 7776000,
"refreshExpiresIn": 7776000,
"tfaKey": "",
"accessMethod": "",
"loginType": ""
}
```

The access token can be fetched from your browser cookies or a 1 liner curl
```bash
curl -v -X POST -H 'Content-Type: application/json' -d '{"account":"YOUR_USER_NAME","password":"YOUR_PASSWORD"}' https://bambulab.com/api/sign-in/form 2>&1 | grep token= | awk '{print$3}'
# Grab the access Token
export MY_TOKEN=AA...

# Grab username (uid) from here
curl -sS --fail -H "Authorization: Bearer ${MY_TOKEN}" https://api.bambulab.com/v1/design-user-service/my/preference | jq '{"username": ("u_" + (.uid | tostring))}'
```

Output:
```json
{
"username": "u_12345"
}
```

Configuration:

```properties
bambu.cloud.enabled=true

# Option1: Let bambufarm login and fetch token
bambu.cloud.login.username=YOUR_LOGIN_USER
bambu.cloud.login.password=YOUR_LOGIN_PASSWORD

# Option2: fetch token via curl and paste here
bambu.cloud.token=FULL_JWT_TOKEN_FROM_COOKIES
bambu.cloud.username=u_12345
bambu.cloud.token=AA...
```

### User Section
Expand Down
4 changes: 0 additions & 4 deletions bambu/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-jwt</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security</artifactId>
Expand Down
9 changes: 1 addition & 8 deletions bambu/src/main/java/com/tfyre/bambu/BambuConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,12 @@ public interface Cloud {
@WithDefault("ssl://us.mqtt.bambulab.com:8883")
String url();

Optional<CloudLogin> login();
Optional<String> username();

Optional<String> token();

}

public interface CloudLogin {

String username();

String password();
}

public interface Dashboard {

@WithDefault("true")
Expand Down
59 changes: 6 additions & 53 deletions bambu/src/main/java/com/tfyre/bambu/CloudService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
import java.util.Optional;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.resteasy.reactive.RestResponse;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.jwt.consumer.JwtContext;

/**
*
Expand All @@ -28,59 +24,16 @@ public Optional<Data> getLoginData() {
if (!config.cloud().enabled()) {
return Optional.empty();
}

if (config.cloud().token().isPresent()) {
Log.info("token login");
return config.cloud().token()
.flatMap(token -> toUserName(token)
.map(username -> new Data(username, token))
);
}

if (config.cloud().login().isEmpty()) {
Log.error("bambu.cloud.(login|token) should be configured, cannot enable cloud mode");
if (config.cloud().username().isEmpty()) {
Log.error("bambu.cloud.username should be configured, cannot enable cloud mode");
return Optional.empty();
}
final BambuConfig.CloudLogin login = config.cloud().login().orElseThrow();

final RestResponse<String> response = api
.login(new CloudApi.Login(login.username(), login.password()))
.await().indefinitely();

if (response.getStatus() != 200) {
Log.errorf("Invalid response status[%d], cannot enable cloud mode", response.getStatus());
if (config.cloud().token().isEmpty()) {
Log.error("bambu.cloud.token should be configured, cannot enable cloud mode");
return Optional.empty();
}

final String token = Optional.ofNullable(response.getCookies())
.map(map -> map.get("token"))
.map(cookie -> cookie.getValue())
.orElse("");

if (token.isEmpty()) {
Log.errorf("Could not find 'token' in cookie, cannot enable cloud mode");
return Optional.empty();
}

return toUserName(token)
.map(username -> new Data(username, token));
}

Optional<String> toUserName(final String token) {
Log.info("mapping username");
final JwtConsumer consumer = new JwtConsumerBuilder()
.setSkipSignatureVerification()
.setSkipAllDefaultValidators()
.build();
final JwtContext context;
try {
context = consumer.process(token);
} catch (InvalidJwtException ex) {
Log.errorf(ex, "Could not parse token: %s", ex.getMessage());
return Optional.empty();
}
return Optional.ofNullable(context.getJwtClaims().getClaimValueAsString("username"));

Log.info("username & token login");
return Optional.of(new Data(config.cloud().username().get(), config.cloud().token().get()));
}

public record Data(String username, String password) {
Expand Down

0 comments on commit 5412a62

Please sign in to comment.