Skip to content

fix(msteams): fetch OneDrive/SharePoint shared media via Graph shares endpoint (#55383)#63942

Merged
BradGroux merged 3 commits intoopenclaw:mainfrom
sudie-codes:fix/msteams-onedrive-media-fetch-55383
Apr 10, 2026
Merged

fix(msteams): fetch OneDrive/SharePoint shared media via Graph shares endpoint (#55383)#63942
BradGroux merged 3 commits intoopenclaw:mainfrom
sudie-codes:fix/msteams-onedrive-media-fetch-55383

Conversation

@sudie-codes
Copy link
Copy Markdown
Contributor

Summary

Files shared from OneDrive/SharePoint into Teams now resolve correctly via the Graph /shares/{shareId}/driveItem/content endpoint instead of returning empty content.

Root cause

When a user shared a OneDrive or SharePoint file in a 1:1 Teams DM, the attachment arrived in activity.attachments with contentType: "reference" and contentUrl pointing to a SharePoint/OneDrive landing URL. The direct-download path (downloadMSTeamsAttachments) treated it as a regular URL and fetched it directly, which returns an HTML landing page (or empty body) rather than the file bytes.

The Graph fallback in downloadMSTeamsGraphMedia already knew how to handle reference attachments, but it only ran when the message also contained an HTML attachment (image/video inline paste path). 1:1 DMs with just a reference attachment never hit the working path.

Fix

  • Add isGraphSharedLinkUrl, encodeGraphShareId, and tryBuildGraphSharesUrlForSharedLink helpers in attachments/shared.ts that detect SharePoint/OneDrive hosts (including GCC/DoD and 1drv.ms) and build the GET /shares/{u!base64url(url)}/driveItem/content URL per the Graph spec.
  • Rewrite the URL in resolveDownloadCandidate when the direct attachment is a SharePoint/OneDrive shared link. The existing auth fallback in fetchWithAuthFallback already promotes the Graph scope for graph.microsoft.com hosts, so the rewritten request picks up the app's Graph token on auth retry.
  • Refactor attachments/graph.ts reference-attachment branch to use the shared encodeGraphShareId helper so both paths stay in sync.
  • Fall through to the existing fetch path for non-shared URLs.

Fixes #55383

Test plan

  • Unit tests for isGraphSharedLinkUrl across SharePoint (.com/.us/.cn/-df.com), 1drv.ms, onedrive.live.com, onedrive.com, and negative cases
  • Unit tests for encodeGraphShareId verifying u! prefix, base64url alphabet (no +///=), and round-trip
  • Unit tests for tryBuildGraphSharesUrlForSharedLink on SharePoint, OneDrive, and non-shared URLs
  • End-to-end downloadMSTeamsAttachments test confirms SharePoint / OneDrive reference attachments route through graph.microsoft.com/v1.0/shares/... with the Graph-scoped token
  • Fall-through test confirms non-shared URLs continue to use the original direct fetch path
  • Manual: share a SharePoint file to a Teams 1:1 chat with the bot

@openclaw-barnacle openclaw-barnacle Bot added channel: msteams Channel integration: msteams size: M labels Apr 9, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 526cb5943b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!host) {
return false;
}
return GRAPH_SHARED_LINK_HOST_SUFFIXES.some((suffix) => host === suffix || host.endsWith(suffix));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Tighten shared-link host suffix matching

isGraphSharedLinkUrl uses host.endsWith(suffix) for every suffix, so entries without a leading dot (onedrive.com, 1drv.ms) also match unrelated hostnames like notonedrive.com and evil1drv.ms. In resolveDownloadCandidate this misclassification rewrites those URLs to graph.microsoft.com/shares/..., which bypasses the original attachment-host allowlist check (the rewritten Graph URL is allowed) and triggers Graph-token fetch attempts for links that should be rejected. Matching should require a label boundary (for example host === suffix || host.endsWith('.' + suffix)) for bare-domain suffixes.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 9, 2026

Greptile Summary

This PR fixes OneDrive/SharePoint shared-file downloads in Teams 1:1 DMs by rewriting the attachment contentUrl to the Graph /shares/{shareId}/driveItem/content endpoint in resolveDownloadCandidate, and extracts the shared helper encodeGraphShareId for reuse in graph.ts. The core fix is correct for the 1:1 DM (download.ts) path.

  • onedrive.live.com silently dropped in group chats (graph.ts): GRAPH_SHARED_LINK_HOST_SUFFIXES now includes onedrive.live.com, but DEFAULT_MEDIA_HOST_ALLOWLIST does not. The isUrlAllowed(shareUrl, policy.allowHosts) guard in graph.ts line 328 checks the original URL before building the shares URL — so group-chat messages with onedrive.live.com reference attachments are silently skipped. The fix is to add \"onedrive.live.com\" to DEFAULT_MEDIA_HOST_ALLOWLIST, or adopt the same rewrite-first approach from download.ts in the graph path.

Confidence Score: 4/5

Safe to merge for the 1:1 DM fix, but onedrive.live.com attachments in group chats will still silently fail due to the allowlist gap.

The 1:1 DM fix is correct and well-tested. One P1 gap: onedrive.live.com is added to GRAPH_SHARED_LINK_HOST_SUFFIXES (implying support) but is absent from DEFAULT_MEDIA_HOST_ALLOWLIST, causing the graph.ts group-chat path to silently skip these attachments. The fix is a one-liner addition to the allowlist.

extensions/msteams/src/attachments/shared.ts (DEFAULT_MEDIA_HOST_ALLOWLIST) and extensions/msteams/src/attachments/graph.ts (isUrlAllowed guard)

Comments Outside Diff (1)

  1. extensions/msteams/src/attachments/graph.ts, line 326-331 (link)

    P1 isUrlAllowed on original URL blocks hosts not in allowlist

    This guard checks the original shareUrl before building the shares URL. Because onedrive.live.com is absent from DEFAULT_MEDIA_HOST_ALLOWLIST, group-chat messages with onedrive.live.com reference attachments silently hit continue here and are never downloaded — even though the actual fetch would go to graph.microsoft.com.

    Consider adopting the same rewrite-first approach used in download.ts for consistency, and as a bonus this also avoids encoding non-SharePoint reference URLs as share IDs:

    const shareUrl = att.contentUrl!;
    const sharesUrl = tryBuildGraphSharesUrlForSharedLink(shareUrl);
    if (!sharesUrl) {
      continue;
    }
    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: extensions/msteams/src/attachments/graph.ts
    Line: 326-331
    
    Comment:
    **`isUrlAllowed` on original URL blocks hosts not in allowlist**
    
    This guard checks the original `shareUrl` before building the shares URL. Because `onedrive.live.com` is absent from `DEFAULT_MEDIA_HOST_ALLOWLIST`, group-chat messages with `onedrive.live.com` reference attachments silently hit `continue` here and are never downloaded — even though the actual fetch would go to `graph.microsoft.com`.
    
    Consider adopting the same rewrite-first approach used in `download.ts` for consistency, and as a bonus this also avoids encoding non-SharePoint reference URLs as share IDs:
    
    ```typescript
    const shareUrl = att.contentUrl!;
    const sharesUrl = tryBuildGraphSharesUrlForSharedLink(shareUrl);
    if (!sharesUrl) {
      continue;
    }
    ```
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/msteams/src/attachments/shared.ts
Line: 95-104

Comment:
**`onedrive.live.com` missing from `DEFAULT_MEDIA_HOST_ALLOWLIST`**

`onedrive.live.com` is added to `GRAPH_SHARED_LINK_HOST_SUFFIXES` here, but it does not appear in `DEFAULT_MEDIA_HOST_ALLOWLIST` (neither as an exact entry nor matched by the `"onedrive.com"` suffix, since `"onedrive.live.com".endsWith("onedrive.com")` is `false`).

In `graph.ts` (the group-chat path), `isUrlAllowed(shareUrl, policy.allowHosts)` is checked against the **original** `contentUrl` before building the `sharesUrl`. Because `onedrive.live.com` is not in the allowlist, that guard silently skips every `onedrive.live.com` reference attachment in group chats. The `download.ts` (1:1 DM) path is unaffected because `resolveDownloadCandidate` rewrites the URL to `graph.microsoft.com` before the allowlist check.

Adding `onedrive.live.com` to `GRAPH_SHARED_LINK_HOST_SUFFIXES` implies it is fully handled, but the group-chat path will drop these attachments without error. The fix requires also adding `"onedrive.live.com"` to `DEFAULT_MEDIA_HOST_ALLOWLIST` (around line 56).

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/msteams/src/attachments/graph.ts
Line: 326-331

Comment:
**`isUrlAllowed` on original URL blocks hosts not in allowlist**

This guard checks the original `shareUrl` before building the shares URL. Because `onedrive.live.com` is absent from `DEFAULT_MEDIA_HOST_ALLOWLIST`, group-chat messages with `onedrive.live.com` reference attachments silently hit `continue` here and are never downloaded — even though the actual fetch would go to `graph.microsoft.com`.

Consider adopting the same rewrite-first approach used in `download.ts` for consistency, and as a bonus this also avoids encoding non-SharePoint reference URLs as share IDs:

```typescript
const shareUrl = att.contentUrl!;
const sharesUrl = tryBuildGraphSharesUrlForSharedLink(shareUrl);
if (!sharesUrl) {
  continue;
}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(msteams): fetch OneDrive/SharePoint ..." | Re-trigger Greptile

Comment on lines +95 to +104
const GRAPH_SHARED_LINK_HOST_SUFFIXES = [
".sharepoint.com",
".sharepoint.us",
".sharepoint.de",
".sharepoint.cn",
".sharepoint-df.com",
"1drv.ms",
"onedrive.live.com",
"onedrive.com",
] as const;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 onedrive.live.com missing from DEFAULT_MEDIA_HOST_ALLOWLIST

onedrive.live.com is added to GRAPH_SHARED_LINK_HOST_SUFFIXES here, but it does not appear in DEFAULT_MEDIA_HOST_ALLOWLIST (neither as an exact entry nor matched by the "onedrive.com" suffix, since "onedrive.live.com".endsWith("onedrive.com") is false).

In graph.ts (the group-chat path), isUrlAllowed(shareUrl, policy.allowHosts) is checked against the original contentUrl before building the sharesUrl. Because onedrive.live.com is not in the allowlist, that guard silently skips every onedrive.live.com reference attachment in group chats. The download.ts (1:1 DM) path is unaffected because resolveDownloadCandidate rewrites the URL to graph.microsoft.com before the allowlist check.

Adding onedrive.live.com to GRAPH_SHARED_LINK_HOST_SUFFIXES implies it is fully handled, but the group-chat path will drop these attachments without error. The fix requires also adding "onedrive.live.com" to DEFAULT_MEDIA_HOST_ALLOWLIST (around line 56).

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/msteams/src/attachments/shared.ts
Line: 95-104

Comment:
**`onedrive.live.com` missing from `DEFAULT_MEDIA_HOST_ALLOWLIST`**

`onedrive.live.com` is added to `GRAPH_SHARED_LINK_HOST_SUFFIXES` here, but it does not appear in `DEFAULT_MEDIA_HOST_ALLOWLIST` (neither as an exact entry nor matched by the `"onedrive.com"` suffix, since `"onedrive.live.com".endsWith("onedrive.com")` is `false`).

In `graph.ts` (the group-chat path), `isUrlAllowed(shareUrl, policy.allowHosts)` is checked against the **original** `contentUrl` before building the `sharesUrl`. Because `onedrive.live.com` is not in the allowlist, that guard silently skips every `onedrive.live.com` reference attachment in group chats. The `download.ts` (1:1 DM) path is unaffected because `resolveDownloadCandidate` rewrites the URL to `graph.microsoft.com` before the allowlist check.

Adding `onedrive.live.com` to `GRAPH_SHARED_LINK_HOST_SUFFIXES` implies it is fully handled, but the group-chat path will drop these attachments without error. The fix requires also adding `"onedrive.live.com"` to `DEFAULT_MEDIA_HOST_ALLOWLIST` (around line 56).

How can I resolve this? If you propose a fix, please make it concise.

@BradGroux BradGroux merged commit 4fc5016 into openclaw:main Apr 10, 2026
40 of 42 checks passed
steipete pushed a commit that referenced this pull request Apr 10, 2026
… endpoint (#55383) (#63942)

* fix(msteams): fetch OneDrive/SharePoint media via Graph shares endpoint (#55383)

* fix(msteams): rewrite shared links before allowlist check

* test(msteams): fix typed fetch call assertions

---------

Co-authored-by: Brad Groux <bradgroux@users.noreply.github.com>
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
… endpoint (openclaw#55383) (openclaw#63942)

* fix(msteams): fetch OneDrive/SharePoint media via Graph shares endpoint (openclaw#55383)

* fix(msteams): rewrite shared links before allowlist check

* test(msteams): fix typed fetch call assertions

---------

Co-authored-by: Brad Groux <bradgroux@users.noreply.github.com>
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
… endpoint (openclaw#55383) (openclaw#63942)

* fix(msteams): fetch OneDrive/SharePoint media via Graph shares endpoint (openclaw#55383)

* fix(msteams): rewrite shared links before allowlist check

* test(msteams): fix typed fetch call assertions

---------

Co-authored-by: Brad Groux <bradgroux@users.noreply.github.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
… endpoint (openclaw#55383) (openclaw#63942)

* fix(msteams): fetch OneDrive/SharePoint media via Graph shares endpoint (openclaw#55383)

* fix(msteams): rewrite shared links before allowlist check

* test(msteams): fix typed fetch call assertions

---------

Co-authored-by: Brad Groux <bradgroux@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[msteams] Inbound media from OneDrive/SharePoint shared links fails — graph media fetch empty

2 participants