ObjMatrix  Check-in [1e716c7f85]

Overview
Comment:Add MTXRequest, MTXClient & support for logging in
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 1e716c7f85cbebd8a6cdddaee2605897beeb69d0a20150ab5a300254007648e4
User & Date: js on 2020-10-03 14:23:04
Other Links: manifest | tags
Context
2020-10-03
14:47
Remove ObjSQLite3 dependency until it's used check-in: 8d796cb21f user: js tags: trunk
14:23
Add MTXRequest, MTXClient & support for logging in check-in: 1e716c7f85 user: js tags: trunk
09:59
Use rpath for ObjFW/ObjOpenSSL/ObjSQLite3 check-in: 1fa7ea5521 user: js tags: trunk
Changes

Modified .fossil-settings/ignore-glob from [e59368143d] to [2f52ddd303].

13
14
15
16
17
18
19

aclocal.m4
autom4te.cache
buildsys.mk
config.log
config.status
configure
extra.mk








>
13
14
15
16
17
18
19
20
aclocal.m4
autom4te.cache
buildsys.mk
config.log
config.status
configure
extra.mk
tests/tests

Modified extra.mk.in from [7d1657d38e] to [ce5a64be0d].

1
2
3
4
5

6
7
8
9
10
11
12
13
OBJMATRIX_SHARED_LIB = @OBJMATRIX_SHARED_LIB@
OBJMATRIX_STATIC_LIB = @OBJMATRIX_STATIC_LIB@
OBJMATRIX_FRAMEWORK = @OBJMATRIX_FRAMEWORK@
OBJMATRIX_LIB_MAJOR = 0
OBJMATRIX_LIB_MINOR = 0


EXCEPTIONS_A = @EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_A = @EXCEPTIONS_EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_LIB_A = @EXCEPTIONS_EXCEPTIONS_LIB_A@
EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@
LIBOBJMATRIX_DEP = @LIBOBJMATRIX_DEP@
OBJFW_CONFIG = @OBJFW_CONFIG@
RUN_TESTS = @RUN_TESTS@





>








1
2
3
4
5
6
7
8
9
10
11
12
13
14
OBJMATRIX_SHARED_LIB = @OBJMATRIX_SHARED_LIB@
OBJMATRIX_STATIC_LIB = @OBJMATRIX_STATIC_LIB@
OBJMATRIX_FRAMEWORK = @OBJMATRIX_FRAMEWORK@
OBJMATRIX_LIB_MAJOR = 0
OBJMATRIX_LIB_MINOR = 0
OBJMATRIX_LIB_MAJOR_MINOR = ${OBJMATRIX_LIB_MAJOR_MINOR}.${OBJMATRIX_LIB_MINOR}

EXCEPTIONS_A = @EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_A = @EXCEPTIONS_EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_LIB_A = @EXCEPTIONS_EXCEPTIONS_LIB_A@
EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@
LIBOBJMATRIX_DEP = @LIBOBJMATRIX_DEP@
OBJFW_CONFIG = @OBJFW_CONFIG@
RUN_TESTS = @RUN_TESTS@

Added src/MTXClient.h version [f435b302a4].



































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * Copyright (c) 2020, Jonathan Schleifer <js@nil.im>
 *
 * https://fossil.nil.im/objmatrix
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import <ObjFW/ObjFW.h>

OF_ASSUME_NONNULL_BEGIN

@class MTXClient;

/**
 * @brief A block called when a new login succeeded or failed.
 *
 * @param client If the login succeeded, the newly created client
 * @param exception If the login failed, an exception
 */
typedef void (^mtx_client_login_block_t)(MTXClient *_Nullable client,
    id _Nullable exception);

/**
 * @brief A class that represents a client.
 */
@interface MTXClient: OFObject
/**
 * @brief The user ID used by the client.
 */
@property (readonly, nonatomic) OFString *userID;

/**
 * @brief The device ID used by the client.
 */
@property (readonly, nonatomic) OFString *deviceID;

/**
 * @brief The access token used by the client.
 */
@property (readonly, nonatomic) OFString *accessToken;

/**
 * @brief The homeserver used by the client.
 */
@property (readonly, nonatomic) OFURL *homeserver;

/**
 * @brief Creates a new client with the specified access token on the specified
 *	  homeserver.
 *
 * @param accessToken The access token for the client
 * @param homeserver The URL of the homeserver
 * @return An autoreleased MTXClient
 */
+ (instancetype)clientWithUserID: (OFString *)userID
			deviceID: (OFString *)deviceID
		     accessToken: (OFString *)accessToken
		      homeserver: (OFURL *)homeserver;

/**
 * @brief Logs into the homeserver and creates a new client.
 */
+ (void)logInWithUser: (OFString *)user
	     password: (OFString *)password
	   homeserver: (OFURL *)homeserver
		block: (mtx_client_login_block_t)block;

/**
 * @brief Initializes an already allocated client with the specified access
 *	  token on the specified homeserver.
 *
 * @param accessToken The access token for the client
 * @param homeserver The URL of the homeserver
 * @return An initialized MTXClient
 */
- (instancetype)initWithUserID: (OFString *)userID
		      deviceID: (OFString *)deviceID
		   accessToken: (OFString *)accessToken
		    homeserver: (OFURL *)homeserver OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END

Added src/MTXClient.m version [bbc38be695].



























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * Copyright (c) 2020, Jonathan Schleifer <js@nil.im>
 *
 * https://fossil.nil.im/objmatrix
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import "MTXClient.h"
#import "MTXRequest.h"

#import "MTXLoginFailedException.h"

static void
validateHomeserver(OFURL *homeserver)
{
	if (![homeserver.scheme isEqual: @"http"] &&
	    ![homeserver.scheme isEqual: @"https"])
		@throw [OFUnsupportedProtocolException
		    exceptionWithURL: homeserver];

	if (homeserver.path != nil && ![homeserver.path isEqual: @"/"])
		@throw [OFInvalidArgumentException exception];

	if (homeserver.user != nil || homeserver.password != nil ||
	    homeserver.query != nil || homeserver.fragment != nil)
		@throw [OFInvalidArgumentException exception];
}

@implementation MTXClient
+ (instancetype)clientWithUserID: (OFString *)userID
			deviceID: (OFString *)deviceID
		     accessToken: (OFString *)accessToken
		      homeserver: (OFURL *)homeserver
{
	return [[[self alloc] initWithUserID: userID
				    deviceID: deviceID
				 accessToken: accessToken
				  homeserver: homeserver] autorelease];
}

+ (void)logInWithUser: (OFString *)user
	     password: (OFString *)password
	   homeserver: (OFURL *)homeserver
		block: (mtx_client_login_block_t)block
{
	void *pool = objc_autoreleasePoolPush();

	validateHomeserver(homeserver);

	MTXRequest *request = [MTXRequest
	    requestWithPath: @"/_matrix/client/r0/login"
		accessToken: nil
		 homeserver: homeserver];
	request.method = OF_HTTP_REQUEST_METHOD_POST;
	request.body = @{
		@"type": @"m.login.password",
		@"identifier": @{
			@"type": @"m.id.user",
			@"user": user
		},
		@"password": password
	};

	[request asyncPerformWithBlock:
	    ^ (OFDictionary<OFString *, id> *response, int statusCode,
	    id exception) {
		if (exception != nil) {
			block(nil, exception);
			return;
		}

		if (statusCode != 200) {
			id exception = [MTXLoginFailedException
			    exceptionWithUser: user
				   homeserver: homeserver
				   statusCode: statusCode
				     response: response];
			block(nil, exception);
			return;
		}

		OFString *userID = response[@"user_id"];
		OFString *deviceID = response[@"device_id"];
		OFString *accessToken = response[@"access_token"];
		if (userID == nil || deviceID == nil ||
		    accessToken == nil) {
			block(nil, [OFInvalidServerReplyException exception]);
			return;
		}

		OFString *baseURL =
		    response[@"well_known"][@"m.homeserver"][@"base_url"];
		OFURL *realHomeserver;
		if (baseURL != nil) {
			@try {
				realHomeserver = [OFURL URLWithString: baseURL];
			} @catch (id e) {
				block(nil, e);
				return;
			}
		} else
			realHomeserver = homeserver;

		MTXClient *client = [MTXClient
		    clientWithUserID: userID
			    deviceID: deviceID
			 accessToken: accessToken
			  homeserver: realHomeserver];
		block(client, nil);
	}];

	objc_autoreleasePoolPop(pool);
}

- (instancetype)initWithUserID: (OFString *)userID
		      deviceID: (OFString *)deviceID
		   accessToken: (OFString *)accessToken
		    homeserver: (OFURL *)homeserver
{
	self = [super init];

	@try {
		validateHomeserver(homeserver);

		_userID = [userID copy];
		_deviceID = [deviceID copy];
		_accessToken = [accessToken copy];
		_homeserver = [homeserver copy];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_userID release];
	[_deviceID release];
	[_accessToken release];
	[_homeserver release];

	[super dealloc];
}

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"<%@\n"
	    @"\tUser ID = %@\n"
	    @"\tDevice ID = %@\n"
	    @"\tAccess token = %@\n"
	    @"\tHomeserver = %@\n"
	    @">",
	    self.class, _userID, _deviceID, _accessToken, _homeserver];
}
@end

Added src/MTXRequest.h version [dd16951835].





















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
 * Copyright (c) 2020, Jonathan Schleifer <js@nil.im>
 *
 * https://fossil.nil.im/objmatrix
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import <ObjFW/ObjFW.h>

OF_ASSUME_NONNULL_BEGIN

/**
 * @brief A block called with the response for an MTXRequest.
 *
 * @param response The response to the request, as a dictionary parsed from JSON
 * @param statusCode The HTTP status code returned for the request
 * @param exception The first exception that occurred during the request,
 *		    or `nil` on success
 */
typedef void (^mtx_request_block_t)(
    OFDictionary<OFString *, id> *_Nullable response, int statusCode,
    id _Nullable exception);

/**
 * @brief An internal class for performing a request on the Matrix server.
 */
@interface MTXRequest: OFObject <OFHTTPClientDelegate>
/**
 * @brief The access token to use.
 *
 * Some requests are unauthenticated - for those, the access token is `nil`.
 */
@property (readonly, nonatomic, nullable) OFString *accessToken;

/**
 * @brief The URL of the homeserver to send the request to.
 */
@property (readonly, nonatomic) OFURL *homeserver;

/**
 * @brief The HTTP request method.
 *
 * Defaults to `OF_HTTP_REQUEST_METHOD_GET`.
 */
@property (nonatomic) of_http_request_method_t method;

/**
 * @brief The path of the request.
 */
@property (copy, nonatomic) OFString *path;

/**
 * @brief An optional body to send along with the request.
 *
 * This is a dictionary that gets serialized to JSON when the request is sent.
 */
@property (copy, nullable, nonatomic) OFDictionary<OFString *, id> *body;

/**
 * @brief Creates a new request with the specified access token and homeserver.
 *
 * @param accessToken An (optional) access token to use
 * @param homeserver The homeserver the request will be sent to
 * @return An autoreleased MTXRequest
 */
+ (instancetype)requestWithPath: (OFString *)path
		    accessToken: (nullable OFString *)accessToken
		     homeserver: (OFURL *)homeserver;

/**
 * @brief Initializes an already allocated request with the specified access
 *	  token and homeserver.
 *
 * @param accessToken An (optional) access token to use
 * @param homeserver The homeserver the request will be sent to
 * @return An initialized MTXRequest
 */
- (instancetype)initWithPath: (OFString *)path
		 accessToken: (nullable OFString *)accessToken
		  homeserver: (OFURL *)homeserver;

/**
 * @brief Performs the request and calls the specified block once the request
 *	  succeeded or failed.
 *
 * @param block The block to call once the request succeeded or failed
 */
- (void)asyncPerformWithBlock: (mtx_request_block_t)block;
@end

OF_ASSUME_NONNULL_END

Added src/MTXRequest.m version [eb5d497f5c].

































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
 * Copyright (c) 2020, Jonathan Schleifer <js@nil.im>
 *
 * https://fossil.nil.im/objmatrix
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import "MTXRequest.h"

@implementation MTXRequest
{
	OFData *_body;
	mtx_request_block_t _block;
}

+ (instancetype)requestWithPath: (OFString *)path
		    accessToken: (OFString *)accessToken
		     homeserver: (OFURL *)homeserver
{
	return [[[self alloc] initWithPath: path
			       accessToken: accessToken
				homeserver: homeserver] autorelease];
}

- (instancetype)initWithPath: (OFString *)path
		 accessToken: (OFString *)accessToken
		  homeserver: (OFURL *)homeserver
{
	self = [super init];

	@try {
		_accessToken = [accessToken copy];
		_homeserver = [homeserver copy];
		_path = [path copy];
		_method = OF_HTTP_REQUEST_METHOD_GET;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_accessToken release];
	[_homeserver release];
	[_path release];
	[_body release];

	[super dealloc];
}

- (void)setBody: (OFDictionary<OFString *, id> *)body
{
	void *pool = objc_autoreleasePoolPush();

	[_body release];

	OFString *JSONString = [body JSONRepresentation];
	_body = [[OFData alloc]
	    initWithItems: JSONString.UTF8String
		    count: JSONString.UTF8StringLength];

	objc_autoreleasePoolPop(pool);
}

- (OFDictionary<OFString *, id> *)body
{
	return [OFString stringWithUTF8String: _body.items
				       length: _body.count]
	    .objectByParsingJSON;
}

- (void)asyncPerformWithBlock: (mtx_request_block_t)block
{
	void *pool = objc_autoreleasePoolPush();

	if (_block != nil)
		/* Not the best exception to indicate it's already in-flight. */
		@throw [OFAlreadyConnectedException exception];

	OFMutableURL *requestURL = [[_homeserver mutableCopy] autorelease];
	requestURL.path = _path;

	OFMutableDictionary *headers = [OFMutableDictionary dictionary];
	headers[@"User-Agent"] = @"ObjMatrix";
	if (_accessToken != nil)
		headers[@"Authentication"] = [OFString
		    stringWithFormat: @"Bearer %@", _accessToken];
	if (_body != nil)
		headers[@"Content-Length"] = @(_body.count).stringValue;

	OFHTTPRequest *request = [OFHTTPRequest requestWithURL: requestURL];
	request.method = _method;
	request.headers = headers;

	OFHTTPClient *client = [OFHTTPClient client];
	client.delegate = self;

	_block = [block copy];
	[self retain];
	[client asyncPerformRequest: request];

	objc_autoreleasePoolPop(pool);
}

-      (void)client: (OFHTTPClient *)client
  didPerformRequest: (OFHTTPRequest *)request
	   response: (OFHTTPResponse *)response
{
	/* Reset to nil first, so that another one can be performed. */
	mtx_request_block_t block = _block;
	_block = nil;

	@try {
		OFMutableData *responseData = [OFMutableData data];
		while (!response.atEndOfStream) {
			char buffer[512];
			size_t length = [response readIntoBuffer: buffer
							  length: 512];

			[responseData addItems: buffer
					 count: length];
		}

		OFDictionary<OFString *, id> *responseJSON =
		    [OFString stringWithUTF8String: responseData.items
					    length: responseData.count]
		    .objectByParsingJSON;

		block(responseJSON, response.statusCode, nil);
	} @catch (id e) {
		block(nil, response.statusCode, e);
	}

	[block release];
	[self release];
}

-	  (void)client: (OFHTTPClient *)client
  didFailWithException: (id)exception
	       request: (OFHTTPRequest *)request
{
	/* Reset to nil first, so that another one can be performed. */
	mtx_request_block_t block = _block;
	_block = nil;

	block(nil, 0, exception);

	[block release];
	[self release];
}

-     (void)client: (OFHTTPClient *)client
  wantsRequestBody: (OFStream *)body
	   request: (OFHTTPRequest *)request
{
	[body writeData: _body];
}
@end

Modified src/Makefile from [8e47e91e59] to [0adfd37e81].

1
2
3
4
5
6
7
8
9
10


11
12
13
14
15
16
17
18
19
20
include ../extra.mk

SUBDIRS = exceptions

SHARED_LIB = ${OBJMATRIX_SHARED_LIB}
STATIC_LIB = ${OBJMATRIX_STATIC_LIB}
FRAMEWORK = ${OBJMATRIX_FRAMEWORK}
LIB_MAJOR = ${OBJMATRIX_LIB_MAJOR}
LIB_MINOR = ${OBJMATRIX_LIB_MINOR}



INCLUDES := ${SRCS:.m=.h}	\
	    ObjMatrix.h

OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_A}
LIB_OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_LIB_A}

include ../buildsys.mk

CPPFLAGS += -I. -Iexceptions
LD = ${OBJC}










>
>










1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
include ../extra.mk

SUBDIRS = exceptions

SHARED_LIB = ${OBJMATRIX_SHARED_LIB}
STATIC_LIB = ${OBJMATRIX_STATIC_LIB}
FRAMEWORK = ${OBJMATRIX_FRAMEWORK}
LIB_MAJOR = ${OBJMATRIX_LIB_MAJOR}
LIB_MINOR = ${OBJMATRIX_LIB_MINOR}

SRCS = MTXClient.m	\
       MTXRequest.m
INCLUDES := ${SRCS:.m=.h}	\
	    ObjMatrix.h

OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_A}
LIB_OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_LIB_A}

include ../buildsys.mk

CPPFLAGS += -I. -Iexceptions
LD = ${OBJC}

Added src/ObjMatrix.h version [82b616f812].

















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * Copyright (c) 2020, Jonathan Schleifer <js@nil.im>
 *
 * https://fossil.nil.im/objmatrix
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import "MTXClient.h"
#import "MTXRequest.h"

Added src/exceptions/MTXLoginFailedException.h version [be4cfcccf8].























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
 * Copyright (c) 2020, Jonathan Schleifer <js@nil.im>
 *
 * https://fossil.nil.im/objmatrix
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import <ObjFW/ObjFW.h>

OF_ASSUME_NONNULL_BEGIN

@interface MTXLoginFailedException: OFException
@property (readonly, nonatomic) OFString *user;
@property (readonly, nonatomic) OFURL *homeserver;
@property (readonly, nonatomic) int statusCode;
@property (readonly, nonatomic) OFDictionary<OFString *, id> *response;

+ (instancetype)exceptionWithUser: (OFString *)user
		       homeserver: (OFURL *)homeserver
		       statusCode: (int)statusCode
			 response: (OFDictionary<OFString *, id> *)response;
- (instancetype)initWithUser: (OFString *)user
		  homeserver: (OFURL *)homeserver
		  statusCode: (int)statusCode
		    response: (OFDictionary<OFString *, id> *)response;
@end

OF_ASSUME_NONNULL_END

Added src/exceptions/MTXLoginFailedException.m version [6ce58b3536].



































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*
 * Copyright (c) 2020, Jonathan Schleifer <js@nil.im>
 *
 * https://fossil.nil.im/objmatrix
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import "MTXLoginFailedException.h"

@implementation MTXLoginFailedException
+ (instancetype)exceptionWithUser: (OFString *)user
		       homeserver: (OFURL *)homeserver
		       statusCode: (int)statusCode
			 response: (OFDictionary<OFString *, id> *)response
{
	return [[[self alloc] initWithUser: user
				homeserver: homeserver
				statusCode: statusCode
				  response: response] autorelease];
}

- (instancetype)initWithUser: (OFString *)user
		  homeserver: (OFURL *)homeserver
		  statusCode: (int)statusCode
		    response: (OFDictionary<OFString *, id> *)response
{
	self = [super init];

	@try {
		_user = [user copy];
		_homeserver = [homeserver copy];
		_statusCode = statusCode;
		_response = [response copy];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_user release];
	[_homeserver release];
	[_response release];

	[super dealloc];
}
@end

Modified src/exceptions/Makefile from [54ff6397e1] to [c62821a6f5].

1
2
3
4
5

6
7
8
9
10
11
include ../../extra.mk

STATIC_PIC_LIB_NOINST = ${EXCEPTIONS_LIB_A}
STATIC_LIB_NOINST = ${EXCEPTIONS_A}


INCLUDES = ${SRCS:.m=.h}

include ../../buildsys.mk

CPPFLAGS += -I. -I..






>






1
2
3
4
5
6
7
8
9
10
11
12
include ../../extra.mk

STATIC_PIC_LIB_NOINST = ${EXCEPTIONS_LIB_A}
STATIC_LIB_NOINST = ${EXCEPTIONS_A}

SRCS = MTXLoginFailedException.m
INCLUDES = ${SRCS:.m=.h}

include ../../buildsys.mk

CPPFLAGS += -I. -I..

Added tests/Makefile version [78699fd8e6].



























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
PROG_NOINST = tests${PROG_SUFFIX}
SRCS = Tests.m

include ../buildsys.mk
include ../extra.mk

post-all: ${RUN_TESTS}

.PHONY: run
run:
	rm -f libobjmatrix.so.${OBJMATRIX_LIB_MAJOR}
	rm -f libobjmatrix.so.${OBJMATRIX_LIB_MAJOR_MINOR}
	rm -f objmatrix.dll libobjmatrix.${OBJMATRIX_LIB_MAJOR}.dylib
	if test -f ../src/libobjmatrix.so; then \
		${LN_S} ../src/libobjmatrix.so \
		    libobjmatrix.so.${OBJMATRIX_LIB_MAJOR}; \
		${LN_S} ../src/libobjmatrix.so \
		    libobjmatrix.so.${OBJMATRIX_LIB_MAJOR_MINOR}; \
	elif test -f ../src/libobjmatrix.so.${OBJMATRIX_LIB_MAJOR_MINOR}; \
	then \
		${LN_S} ../src/libobjmatrix.so.${OBJMATRIX_LIB_MAJOR_MINOR} \
		    libobjmatrix.so.${OBJMATRIX_LIB_MAJOR_MINOR}; \
	fi
	if test -f ../src/objmatrix.dll; then \
		${LN_S} ../src/objmatrix.dll objmatrix.dll; \
	fi
	if test -f ../src/libobjmatrix.dylib; then \
		${LN_S} ../src/libobjmatrix.dylib \
		    libobjmatrix.${OBJMATRIX_LIB_MAJOR}.dylib; \
	fi
	LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \
	DYLD_FRAMEWORK_PATH=../src:../src/runtime$${DYLD_FRAMEWORK_PATH+:}$$DYLD_FRAMEWORK_PATH \
	DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \
	LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \
	${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \
	rm -f libobjmatrix.so.${OBJMATRIX_LIB_MAJOR}; \
	rm -f libobjmatrix.so.${OBJMATRIX_LIB_MAJOR_MINOR} objmatrix.dll; \
	rm -f libobjmatrix.${OBJMATRIX_LIB_MAJOR}.dylib; \
	exit $$EXIT

${PROG_NOINST}: ${LIBOBJMATRIX_DEP}

CPPFLAGS += -I../src
LIBS := -L../src -lobjmatrix ${LIBS}
LD = ${OBJC}

Added tests/tests.m version [b5a188a928].

























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
 * Copyright (c) 2020, Jonathan Schleifer <js@nil.im>
 *
 * https://fossil.nil.im/objmatrix
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import <ObjFW/ObjFW.h>

#import "MTXClient.h"

@interface Tests: OFObject <OFApplicationDelegate>
@end

OF_APPLICATION_DELEGATE(Tests)

@implementation Tests
- (void)applicationDidFinishLaunching
{
	__auto_type environment = OFApplication.environment;
	if (environment[@"OBJMATRIX_USER"] == nil ||
	    environment[@"OBJMATRIX_PASS"] == nil ||
	    environment[@"OBJMATRIX_HS"] == nil) {
		[of_stderr writeString: @"Please set OBJMATRIX_USER, "
					@"OBJMATRIX_PASS and OBJMATRIX_HS in "
					@"the environment!\n"];
		[OFApplication terminateWithStatus: 1];
	}

	OFURL *homeserver = [OFURL URLWithString: environment[@"OBJMATRIX_HS"]];
	[MTXClient logInWithUser: environment[@"OBJMATRIX_USER"]
			password: environment[@"OBJMATRIX_PASS"]
		      homeserver: homeserver
			   block: ^ (MTXClient *client, id exception) {
		if (exception != nil) {
			[of_stdout writeFormat: @"Error logging in: %@\n",
						exception];
			[OFApplication terminateWithStatus: 1];
		}

		[of_stdout writeFormat: @"Logged in client: %@\n", client];
		[OFApplication terminate];
	}];
}
@end