-
-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Content-hashed external URI parsing support #2387
base: main
Are you sure you want to change the base?
Conversation
@@ -32,14 +40,41 @@ UriParseResult _parseActerUri(Uri uri) { | |||
}; | |||
} | |||
|
|||
UriParseResult _parseHttpsUri(Uri uri) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the core of the new scheme
Hey there 👋,
|
@@ -32,14 +40,41 @@ UriParseResult _parseActerUri(Uri uri) { | |||
}; | |||
} | |||
|
|||
UriParseResult _parseHttpsUri(Uri uri) { | |||
if (uri.host == 'matrix.to') { | |||
return _parseMatrixHttpsUri(uri); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
matrix.to is a special case with a special format for legacy links
final hash = uri.pathSegments.lastOrNull; | ||
if (hash == null || hash.isEmpty) { | ||
throw IncorrectHashError(); | ||
} | ||
|
||
final pathWithoutHash = uri.path.substring(0, uri.path.length - hash.length -1); | ||
final strippedUri = uri.replace(path: pathWithoutHash); | ||
final hashableUri = strippedUri.toString(); | ||
final calculatedHash = sha1.convert(utf8.encode(hashableUri)).toString(); | ||
if (calculatedHash != hash) { | ||
throw IncorrectHashError(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- look for the hash
- remove the hash
- compare the hash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example: acter:roomid/room:acter.global/e/someEvent?via=acter.global&via=example.org
becomes https://app.acter.global/p/$HASH?via=acter.global&via=example.org#roomid/room:acter.global/e/someEvent
(where $HASH = SHA1.of(https://app.acter.global/p/?via=acter.global&via=example.org#roomid/room:acter.global/e/someEvent
)
Not quite understand link structure and logic. Sorry but looks complex to me to understand.
final extractableUri = strippedUri.replace(path: strippedUri.fragment, fragment: null); | ||
final result = _parseActerUri(extractableUri); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extract the fragment as the path to just use the existing parsing code
final extractableUri = strippedUri.replace(path: strippedUri.fragment, fragment: null); | ||
final result = _parseActerUri(extractableUri); | ||
if (result.preview.userId == null || result.preview.userId?.isEmpty == true) { | ||
throw MissingUserError(result: result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fail with the result if no userId was found.
|
||
// re-usable test cases | ||
|
||
void acterObjectLinksTests(UriMaker makeUri) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are the same as before, just that we have new UriMaker so we can resuse the same tests suites for multiple "schemes"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #2387 +/- ##
==========================================
+ Coverage 27.86% 27.89% +0.02%
==========================================
Files 617 617
Lines 42261 42279 +18
==========================================
+ Hits 11778 11793 +15
- Misses 30483 30486 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deep-link structure looks complex to me, not sure if I am not getting it well or it is actually complex itself.
|
||
// re-usable test cases | ||
|
||
void acterObjectLinksTests(UriMaker makeUri) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏
group('Testing fallback https://app.acter.global/:-links', () => | ||
newSpecLinksTests(makeUriMakerForPublicPrefix('https://app.acter.global/p/')), | ||
); | ||
|
||
group('Testing https://app.acter.global/ object-links', () => | ||
acterObjectLinksTests(makeUriMakerForPublicPrefix('https://app.acter.global/p/')), | ||
); | ||
|
||
group('Testing https://app.acter.global/ invite-links', () => | ||
acterInviteLinkTests(makeUriMakerForPublicPrefix('https://app.acter.global/p/')), | ||
); | ||
|
||
group('Testing https://app.acter.global/ preview data', () => | ||
acterObjectPreviewTests(makeUriMakerForPublicPrefix('https://app.acter.global/p/')), | ||
); | ||
|
||
group('Testing broken https://app.acter.global/ ', () { | ||
test('faulty hash fails', () async { | ||
expect(() => parseActerUri( | ||
Uri.parse('http://acter.global/p/faultyHash?via=acter.global&via=example.org#roomid/room:acter.global/e/someEvent'), | ||
), | ||
throwsA(TypeMatcher<IncorrectHashError>()), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting bit difficulty to grasp entire logic.
final hash = uri.pathSegments.lastOrNull; | ||
if (hash == null || hash.isEmpty) { | ||
throw IncorrectHashError(); | ||
} | ||
|
||
final pathWithoutHash = uri.path.substring(0, uri.path.length - hash.length -1); | ||
final strippedUri = uri.replace(path: pathWithoutHash); | ||
final hashableUri = strippedUri.toString(); | ||
final calculatedHash = sha1.convert(utf8.encode(hashableUri)).toString(); | ||
if (calculatedHash != hash) { | ||
throw IncorrectHashError(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example: acter:roomid/room:acter.global/e/someEvent?via=acter.global&via=example.org
becomes https://app.acter.global/p/$HASH?via=acter.global&via=example.org#roomid/room:acter.global/e/someEvent
(where $HASH = SHA1.of(https://app.acter.global/p/?via=acter.global&via=example.org#roomid/room:acter.global/e/someEvent
)
Not quite understand link structure and logic. Sorry but looks complex to me to understand.
This PR brings support for providing non matrix-to https links with content hashing support for additional security. These work analogous to the previous
acter:
-style-links but with that entire path put into the#
-fragment (query stays the same, but the order might change) and replacing the path with a final hash of the entire URI in this style without that hash as the final parameter). This allows any server to provide that feature under any domain + path as long as the last path-item is the hash itself.Example:
acter:roomid/room:acter.global/e/someEvent?via=acter.global&via=example.org
becomeshttps://app.acter.global/p/$HASH?via=acter.global&via=example.org#roomid/room:acter.global/e/someEvent
(where$HASH = SHA1.of(https://app.acter.global/p/?via=acter.global&via=example.org#roomid/room:acter.global/e/someEvent
)This ensures that we can a) still parse most information from the URI itself without querying the server and b) ensure that the data wasn't messed with in transit or by any third party compared to the data that the server would be showing under that hash.
To the reviewer:
acter:
and new https-links, that's why the test file looks different