Skip to content
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

feat: mas #2692

Merged
merged 19 commits into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@ on:
workflow_dispatch:
inputs:
tag_version:
type: boolean
description: "Tag Version"
required: true
mas:
type: boolean
description: "Build for Mac App Store"
build_version:
type: string
description: "Build Version, only available when mas is true"

# https://docs.github.com/en/enterprise-cloud@latest/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-build
Expand All @@ -32,6 +39,9 @@ jobs:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
exclude:
- os: ${{ github.event.inputs.mas == 'true' && 'ubuntu-latest' }}
- os: ${{ github.event.inputs.mas == 'true' && 'windows-latest' }}

permissions:
id-token: write
Expand All @@ -41,13 +51,13 @@ jobs:
steps:
- name: Check out Git repository Fully
uses: actions/checkout@v4
if: github.event.inputs.tag_version != '' || github.ref_type == 'tag'
if: github.event.inputs.tag_version == 'true' || github.ref_type == 'tag'
with:
fetch-depth: 0
lfs: true
- name: Check out Git repository
uses: actions/checkout@v4
if: github.event.inputs.tag_version == '' && github.ref_type != 'tag'
if: github.event.inputs.tag_version != 'true' && github.ref_type != 'tag'
with:
fetch-depth: 1
lfs: true
Expand All @@ -73,17 +83,23 @@ jobs:
if: runner.os == 'macOS'
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
BUILD_CERTIFICATE_MAS_BASE64: ${{ secrets.BUILD_CERTIFICATE_MAS_BASE64 }}
BUILD_CERTIFICATE_MASPKG_BASE64: ${{ secrets.BUILD_CERTIFICATE_MASPKG_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
CERTIFICATE_MAS_PATH=$RUNNER_TEMP/build_certificate_mas.p12
CERTIFICATE_MASPKG_PATH=$RUNNER_TEMP/build_certificate_maspkg.p12
PP_PATH=$RUNNER_TEMP/build_pp.provisionprofile
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db

# import certificate and provisioning profile from secrets
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
echo -n "$BUILD_CERTIFICATE_MAS_BASE64" | base64 --decode -o $CERTIFICATE_MAS_PATH
echo -n "$BUILD_CERTIFICATE_MASPKG_BASE64" | base64 --decode -o $CERTIFICATE_MASPKG_PATH
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH

# create temporary keychain
Expand All @@ -93,8 +109,11 @@ jobs:

# import certificate to keychain
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security import $CERTIFICATE_MAS_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security import $CERTIFICATE_MASPKG_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
security find-identity $KEYCHAIN_PATH

# apply provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
Expand All @@ -111,14 +130,24 @@ jobs:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Build (macOS)
if: matrix.os == 'macos-latest'
if: matrix.os == 'macos-latest' && github.event.inputs.mas != 'true'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
KEYCHAIN_PATH: ${{ runner.temp }}/app-signing.keychain-db
OSX_SIGN_KEYCHAIN_PATH: ${{ runner.temp }}/app-signing.keychain-db
OSX_SIGN_IDENTITY: ${{ secrets.OSX_SIGN_IDENTITY }}
run: npm exec turbo run //#build:macos

- name: Build (Mac App Store)
if: matrix.os == 'macos-latest' && github.event.inputs.mas == 'true'
env:
OSX_SIGN_KEYCHAIN_PATH: ${{ runner.temp }}/app-signing.keychain-db
OSX_SIGN_IDENTITY: ${{ secrets.OSX_SIGN_IDENTITY_MAS }}
OSX_SIGN_PROVISIONING_PROFILE_PATH: ${{ runner.temp }}/build_pp.provisionprofile
BUILD_VERSION: ${{ github.event.inputs.build_version }}
run: npm exec turbo run //#build:mas

- name: Build Renderer
if: matrix.os == 'ubuntu-latest'
run: pnpm build:render
Expand All @@ -138,6 +167,7 @@ jobs:
out/make/**/*.exe
out/make/**/*.AppImage
out/make/**/*.yml
out/make/**/*.pkg
dist/manifest.yml
dist/*.tar.gz
retention-days: 90
Expand All @@ -153,8 +183,19 @@ jobs:
out/make/**/*arm64.dmg
retention-days: 90

- name: Upload file (pkg)
uses: actions/upload-artifact@v4
if: matrix.os == 'macos-latest'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
name: mas-pkg
path: |
out/make/**/*.pkg
retention-days: 90

- name: Generate artifact attestation
if: github.ref_type == 'tag' || github.event.inputs.tag_version != ''
if: github.ref_type == 'tag' || github.event.inputs.tag_version == 'true'
continue-on-error: true
uses: actions/attest-build-provenance@v1
with:
Expand All @@ -168,7 +209,7 @@ jobs:
dist/*.tar.gz

- run: npx changelogithub
if: github.ref_type == 'tag' || github.event.inputs.tag_version != ''
if: github.ref_type == 'tag' || github.event.inputs.tag_version == 'true'
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -178,7 +219,7 @@ jobs:
uses: ./.github/actions/setup-version

- name: Create Release Draft
if: github.ref_type == 'tag' || github.event.inputs.tag_version != ''
if: github.ref_type == 'tag' || github.event.inputs.tag_version == 'true'
uses: softprops/action-gh-release@v2
with:
name: v${{ steps.version.outputs.APP_VERSION }}
Expand Down
78 changes: 41 additions & 37 deletions apps/renderer/src/modules/auth/LoginModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,43 +45,47 @@ export const LoginModalContent = (props: LoginModalContentProps) => {
</div>

<LoginWithPassword runtime={runtime} />
<div className="my-3 w-full space-y-2">
<div className="flex items-center justify-center">
<Divider className="flex-1" />
<p className="px-4 text-center text-sm text-muted-foreground">{t("login.or")}</p>
<Divider className="flex-1" />
</div>
</div>
<div className="mb-3 flex items-center justify-center gap-4">
{Object.entries(authProviders || [])
.filter(([key]) => key !== "credential")
.map(([key, provider]) => (
<Tooltip key={key} delayDuration={0}>
<TooltipTrigger>
<MotionButtonBase
onClick={() => {
loginHandler(key, "app")
}}
>
<div
className="center inline-flex rounded-full border p-2.5 duration-200 hover:bg-muted [&_svg]:size-6"
dangerouslySetInnerHTML={{
__html: provider.icon,
}}
style={{
color: provider.color,
}}
/>
</MotionButtonBase>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
{t("login.continueWith", { provider: provider.name })}
</TooltipContent>
</TooltipPortal>
</Tooltip>
))}
</div>
{!process.mas && (
<>
<div className="my-3 w-full space-y-2">
<div className="flex items-center justify-center">
<Divider className="flex-1" />
<p className="px-4 text-center text-sm text-muted-foreground">{t("login.or")}</p>
<Divider className="flex-1" />
</div>
</div>
<div className="mb-3 flex items-center justify-center gap-4">
{Object.entries(authProviders || [])
.filter(([key]) => key !== "credential")
.map(([key, provider]) => (
<Tooltip key={key} delayDuration={0}>
<TooltipTrigger>
<MotionButtonBase
onClick={() => {
loginHandler(key, "app")
}}
>
<div
className="center inline-flex rounded-full border p-2.5 duration-200 hover:bg-muted [&_svg]:size-6"
dangerouslySetInnerHTML={{
__html: provider.icon,
}}
style={{
color: provider.color,
}}
/>
</MotionButtonBase>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>
{t("login.continueWith", { provider: provider.name })}
</TooltipContent>
</TooltipPortal>
</Tooltip>
))}
</div>
</>
)}
</>
)
if (isMobile) {
Expand Down
38 changes: 38 additions & 0 deletions apps/renderer/src/pages/settings/(settings)/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { Button } from "@follow/components/ui/button/index.js"
import { Divider } from "@follow/components/ui/divider/Divider.js"
import { Label } from "@follow/components/ui/label/index.js"
import { signOut } from "@follow/shared/auth"

import { useModalStack } from "~/components/ui/modal/stacked/hooks"
import { AccountManagement } from "~/modules/profile/account-management"
import { EmailManagement } from "~/modules/profile/email-management"
import { ProfileSettingForm } from "~/modules/profile/profile-setting-form"
Expand All @@ -17,6 +21,7 @@ export const loader = defineSettingPageData({
})

export function Component() {
const { present } = useModalStack()
return (
<>
<SettingsTitle />
Expand All @@ -30,6 +35,39 @@ export function Component() {
<AccountManagement />
<UpdatePasswordForm />
<TwoFactor />
{/* TODO: Temporary fake account deletion feature */}
{process.mas && (
<div className="flex items-center justify-between">
<Label>Delete Account</Label>
<Button
variant="outline"
onClick={() => {
present({
title: "Delete Account",
content: () => (
<div className="max-w-96">
<p className="mb-4 text-sm text-zinc-500">
Are you sure you want to delete your account? This action is irreversible
and may take up to two days to take effect.
</p>
<Button
variant="outline"
onClick={async () => {
await signOut()
window.location.reload()
}}
>
Delete
</Button>
</div>
),
})
}}
>
Delete
</Button>
</div>
)}
</div>
</section>
</>
Expand Down
10 changes: 10 additions & 0 deletions build/entitlements.mas.child.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
16 changes: 16 additions & 0 deletions build/entitlements.mas.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
</dict>
</plist>
Loading
Loading