Skip to content
This repository was archived by the owner on Jun 21, 2019. It is now read-only.

Login with password #10

Merged
merged 13 commits into from
Oct 25, 2017
32 changes: 28 additions & 4 deletions src/main/java/io/kamax/matrix/client/AMatrixHttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,14 @@ public _MatrixHomeserver getHomeserver() {
}

@Override
public String getAccessToken() {
return context.getToken();
public Optional<String> getAccessToken() {
return Optional.ofNullable(context.getToken());
}

@Override
public String getAccessTokenOrThrow() {
return getAccessToken()
.orElseThrow(() -> new IllegalStateException("This method can only be used with a valid token."));
}

@Override
Expand Down Expand Up @@ -233,8 +239,6 @@ private void log(HttpRequestBase req) {
protected URIBuilder getPathBuilder(String module, String version, String action) {
URIBuilder builder = context.getHs().getClientEndpoint();
builder.setPath(builder.getPath() + "/_matrix/" + module + "/" + version + action);
builder.setParameter("access_token", context.getToken());
builder.setPath(builder.getPath().replace("{userId}", context.getUser().getId()));
if (context.isVirtualUser()) {
builder.setParameter("user_id", context.getUser().getId());
}
Expand All @@ -250,6 +254,16 @@ protected URIBuilder getMediaPathBuilder(String action) {
return getPathBuilder("media", "v1", action);
}

protected URI getClientPathWithAccessToken(String action) {
try {
URIBuilder builder = getClientPathBuilder(action);
builder.setParameter("access_token", getAccessTokenOrThrow());
return builder.build();
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}

protected URI getClientPath(String action) {
try {
return getClientPathBuilder(action).build();
Expand All @@ -258,6 +272,16 @@ protected URI getClientPath(String action) {
}
}

protected URI getMediaPathWithAccessToken(String action) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Has nothing to do with the login feature
  • No media retrieval requires a token if following the CS spec. While I would definitely add this down the road, it's out of scope here and premature I think

try {
URIBuilder builder = getMediaPathBuilder(action);
builder.setParameter("access_token", getAccessTokenOrThrow());
return builder.build();
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}

protected URI getMediaPath(String action) {
try {
return getMediaPathBuilder(action).build();
Expand Down
39 changes: 37 additions & 2 deletions src/main/java/io/kamax/matrix/client/MatrixClientContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,41 @@
import io.kamax.matrix._MatrixID;
import io.kamax.matrix.hs._MatrixHomeserver;

import java.util.Optional;

public class MatrixClientContext {

private _MatrixHomeserver hs;
private _MatrixID user;
private String token;
private boolean isVirtualUser;
private String deviceId;

public MatrixClientContext(_MatrixHomeserver hs, _MatrixID user, String token) {
this(hs, user, token, false);
}

public MatrixClientContext(_MatrixHomeserver hs, _MatrixID user, String token, boolean isVirtualUser) {
this.hs = hs;
this.user = user;
this(hs, user, isVirtualUser);
this.token = token;
}

public MatrixClientContext(_MatrixHomeserver hs) {
this(hs, false);
}

public MatrixClientContext(_MatrixHomeserver hs, String deviceId) {
this(hs, false);
this.deviceId = deviceId;
}

private MatrixClientContext(_MatrixHomeserver hs, _MatrixID user, boolean isVirtualUser) {
this(hs, isVirtualUser);
this.user = user;
}

private MatrixClientContext(_MatrixHomeserver hs, boolean isVirtualUser) {
this.hs = hs;
this.isVirtualUser = isVirtualUser;
}

Expand All @@ -49,12 +69,27 @@ public _MatrixID getUser() {
return user;
}

public void setUser(_MatrixID user) {
this.user = user;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public boolean isVirtualUser() {
return isVirtualUser;
}

public Optional<String> getDeviceId() {
return Optional.ofNullable(deviceId);
}

public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private synchronized void load() {
if (!StringUtils.equalsIgnoreCase("mxc", address.getScheme())) {
log.debug("{} is not a supported protocol for avatars, ignoring", address.getScheme());
} else {
URI path = getMediaPath("/download/" + address.getHost() + address.getPath());
URI path = getMediaPathWithAccessToken("/download/" + address.getHost() + address.getPath());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to login feature


MatrixHttpRequest request = new MatrixHttpRequest(new HttpGet(path));
result = executeContentRequest(request);
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/io/kamax/matrix/client/MatrixHttpRoom.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ public class MatrixHttpRoom extends AMatrixHttpClient implements _MatrixRoom {

public MatrixHttpRoom(MatrixClientContext context, String roomId) {
super(context);

this.roomId = roomId;
}

@Override
protected URIBuilder getClientPathBuilder(String action) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was it removed?

URIBuilder builder = super.getClientPathBuilder(action);
builder.setPath(builder.getPath().replace("{roomId}", roomId));
Expand All @@ -69,7 +69,7 @@ public String getAddress() {

@Override
public Optional<String> getName() {
URI path = getClientPath("/rooms/{roomId}/state/m.room.name");
URI path = getClientPathWithAccessToken("/rooms/{roomId}/state/m.room.name");

MatrixHttpRequest request = new MatrixHttpRequest(new HttpGet(path));
request.addIgnoredErrorCode(404);
Expand All @@ -79,7 +79,7 @@ public Optional<String> getName() {

@Override
public Optional<String> getTopic() {
URI path = getClientPath("/rooms/{roomId}/state/m.room.topic");
URI path = getClientPathWithAccessToken("/rooms/{roomId}/state/m.room.topic");
MatrixHttpRequest matrixRequest = new MatrixHttpRequest(new HttpGet(path));
matrixRequest.addIgnoredErrorCode(404);
String body = execute(matrixRequest);
Expand All @@ -88,13 +88,13 @@ public Optional<String> getTopic() {

@Override
public void join() {
URI path = getClientPath("/rooms/{roomId}/join");
URI path = getClientPathWithAccessToken("/rooms/{roomId}/join");
execute(new HttpPost(path));
}

@Override
public void leave() {
URI path = getClientPath("/rooms/{roomId}/leave");
URI path = getClientPathWithAccessToken("/rooms/{roomId}/leave");
MatrixHttpRequest request = new MatrixHttpRequest(new HttpPost(path));

// TODO Find a better way to handle room objects for unknown rooms
Expand All @@ -109,7 +109,7 @@ public void leave() {
}

private void sendMessage(RoomMessageTextPutBody content) {
URI path = getClientPath("/rooms/{roomId}/send/m.room.message/" + System.currentTimeMillis());
URI path = getClientPathWithAccessToken("/rooms/{roomId}/send/m.room.message/" + System.currentTimeMillis());
HttpPut httpPut = new HttpPut(path);
httpPut.setEntity(getJsonEntity(content));
execute(httpPut);
Expand Down Expand Up @@ -145,7 +145,7 @@ public void invite(_MatrixID mxId) {

@Override
public List<_MatrixID> getJoinedUsers() {
URI path = getClientPath("/rooms/{roomId}/joined_members");
URI path = getClientPathWithAccessToken("/rooms/{roomId}/joined_members");
String body = execute(new HttpGet(path));

List<_MatrixID> ids = new ArrayList<>();
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/io/kamax/matrix/client/MatrixHttpUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public _MatrixID getId() {

@Override
public Optional<String> getName() {
URI path = getClientPath("/profile/" + mxId.getId() + "/displayname");
URI path = getClientPathWithAccessToken("/profile/" + mxId.getId() + "/displayname");

MatrixHttpRequest request = new MatrixHttpRequest(new HttpGet(path));
request.addIgnoredErrorCode(404);
Expand All @@ -61,7 +61,7 @@ public Optional<String> getName() {

@Override
public Optional<_MatrixContent> getAvatar() {
URI path = getClientPath("/profile/" + mxId.getId() + "/avatar_url");
URI path = getClientPathWithAccessToken("/profile/" + mxId.getId() + "/avatar_url");

MatrixHttpRequest request = new MatrixHttpRequest(new HttpGet(path));
request.addIgnoredErrorCode(404);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* matrix-java-sdk - Matrix Client SDK for Java
* Copyright (C) 2017 Arne Augenstein
*
* https://max.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package io.kamax.matrix.client;

public class MatrixPasswordLoginCredentials {
private final String localPart;
private final String password;

public MatrixPasswordLoginCredentials(String localPart, String password) {
this.localPart = localPart;
this.password = password;
}

public String getLocalPart() {
return localPart;
}

public String getPassword() {
return password;
}
}
8 changes: 8 additions & 0 deletions src/main/java/io/kamax/matrix/client/_MatrixClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import io.kamax.matrix._MatrixUser;
import io.kamax.matrix.hs._MatrixRoom;

import java.util.Optional;

public interface _MatrixClient extends _MatrixClientRaw {

void setDisplayName(String name);
Expand All @@ -32,4 +34,10 @@ public interface _MatrixClient extends _MatrixClientRaw {

_MatrixUser getUser(_MatrixID mxId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be optional as well now?


Optional<String> getDeviceId();

void login(MatrixPasswordLoginCredentials credentials);

void logout();

}
7 changes: 5 additions & 2 deletions src/main/java/io/kamax/matrix/client/_MatrixClientRaw.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@
import io.kamax.matrix._MatrixID;
import io.kamax.matrix.hs._MatrixHomeserver;

import java.util.Optional;

public interface _MatrixClientRaw {

MatrixClientContext getContext();

_MatrixHomeserver getHomeserver();

String getAccessToken();
Optional<String> getAccessToken();

_MatrixID getUser();
String getAccessTokenOrThrow();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this should be in the interface. While the implementation is useful, seems like bloat for "external" use with a specific exception forced.


_MatrixID getUser();
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ public MatrixApplicationServiceClient(_MatrixHomeserver hs, String token, String

private MatrixHttpClient createClient(String localpart) {
return new MatrixHttpClient(
new MatrixClientContext(getHomeserver(), getMatrixId(localpart), getAccessToken(), true));
new MatrixClientContext(getHomeserver(), getMatrixId(localpart), getAccessTokenOrThrow(), true));
}

@Override
public _MatrixClient createUser(String localpart) {
log.debug("Creating new user {}", localpart);
URI path = getClientPath("/register");
URI path = getClientPathWithAccessToken("/register");
HttpPost req = new HttpPost(path);
req.setEntity(getJsonEntity(new VirtualUserRegistrationBody(localpart)));
execute(req);
Expand Down
40 changes: 35 additions & 5 deletions src/main/java/io/kamax/matrix/client/regular/MatrixHttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@
import io.kamax.matrix._MatrixUser;
import io.kamax.matrix.client.*;
import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.matrix.json.LoginPostBody;
import io.kamax.matrix.json.LoginResponse;
import io.kamax.matrix.json.UserDisplaynameSetBody;

import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.util.Optional;

public class MatrixHttpClient extends AMatrixHttpClient implements _MatrixClient {

private Logger log = LoggerFactory.getLogger(MatrixHttpClient.class);

public MatrixHttpClient(MatrixClientContext context) {
super(context);
}
Expand All @@ -47,7 +47,7 @@ protected _MatrixID getMatrixId(String localpart) {

@Override
public void setDisplayName(String name) {
URI path = getClientPath("/profile/{userId}/displayname");
URI path = getClientPathWithAccessToken("/profile/" + context.getUser().getId() + "/displayname");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{userId} should remain, just like {roomId} remained

HttpPut req = new HttpPut(path);
req.setEntity(getJsonEntity(new UserDisplaynameSetBody(name)));
execute(req);
Expand All @@ -63,4 +63,34 @@ public _MatrixUser getUser(_MatrixID mxId) {
return new MatrixHttpUser(getContext(), mxId);
}

@Override
public Optional<String> getDeviceId() {
return context.getDeviceId();
}

@Override
public void login(MatrixPasswordLoginCredentials credentials) {
HttpPost request = new HttpPost(getClientPath("/login"));
if (context.getDeviceId().isPresent()) {
request.setEntity(getJsonEntity(new LoginPostBody(credentials.getLocalPart(), credentials.getPassword(),
context.getDeviceId().get())));
} else {
request.setEntity(getJsonEntity(new LoginPostBody(credentials.getLocalPart(), credentials.getPassword())));
}

String body = execute(request);
LoginResponse response = gson.fromJson(body, LoginResponse.class);
context.setToken(response.getAccessToken());
context.setDeviceId(response.getDeviceId());
context.setUser(new MatrixID(credentials.getLocalPart(), context.getHs().getDomain()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per spec, the Matrix ID of the user is returned in the response body, so we should not build it ourself.

}

@Override
public void logout() {
URI path = getClientPathWithAccessToken("/logout");
HttpPost req = new HttpPost(path);
execute(req);
context.setToken(null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about Device ID and User ID?

}

}
Loading