From 427242499d07cc7f64088750184646e3fb07c620 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Thu, 14 May 2026 15:23:38 -0400 Subject: [PATCH] Initial file-share stack CDK stack deploying a t4g.small EC2 instance with Samba and FileBrowser for personal file storage over the site-to-site VPN. Includes 500 GiB gp3 data volume with daily DLM snapshots. --- .github/workflows/ci.yaml | 8 + .github/workflows/deploy.yaml | 18 ++ .gitignore | 5 + README.md | 63 ++++ bin/app.ts | 11 + cdk.context.json | 47 +++ cdk.json | 21 ++ lib/file-share-stack.ts | 212 ++++++++++++++ package-lock.json | 521 ++++++++++++++++++++++++++++++++++ package.json | 24 ++ tsconfig.json | 24 ++ 11 files changed, 954 insertions(+) create mode 100644 .github/workflows/ci.yaml create mode 100644 .github/workflows/deploy.yaml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 bin/app.ts create mode 100644 cdk.context.json create mode 100644 cdk.json create mode 100644 lib/file-share-stack.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 tsconfig.json diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..1846096 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,8 @@ +name: CI +on: + pull_request: + branches: [main] + +jobs: + ci: + uses: Sea-Haven-Industries/.github/.github/workflows/ci-typescript-cdk.yaml@main diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..e5462cf --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,18 @@ +name: Deploy +on: + push: + branches: [main] + +permissions: + id-token: write + contents: read + +concurrency: + group: deploy + cancel-in-progress: false + +jobs: + deploy: + uses: Sea-Haven-Industries/.github/.github/workflows/cd-cdk.yaml@main + secrets: + deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b305898 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +cdk.out/ +*.js +*.d.ts +*.js.map diff --git a/README.md b/README.md new file mode 100644 index 0000000..0c2c433 --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# file-share + +Personal file share server on AWS — Samba for macOS Finder integration and FileBrowser for web-based file management. Accessible exclusively over the site-to-site VPN. + +## Architecture + +- **EC2** — `t4g.small` (ARM64, Amazon Linux 2023) in the private subnet +- **Samba** — SMB file share at `/data/share`, optimized for macOS (`vfs_fruit`) +- **FileBrowser** — Web UI on port 8080, backed by the same `/data/share` directory +- **EBS** — 500 GiB gp3 data volume (separate from root), encrypted +- **DLM** — Daily EBS snapshots, 30-day retention +- **SSM** — Session Manager for instance access (no SSH key) + +## Access + +Requires VPN connection to the office network (10.10.0.0/16). + +### Finder (SMB) + +1. Finder > Go > Connect to Server +2. Enter `smb:///files` +3. Authenticate with `adam` and the password from `file-share/smb-password` in Secrets Manager + +### FileBrowser (Web) + +Open `http://:8080` in a browser. + +## Secrets + +Both stored in AWS Secrets Manager: + +| Secret | Purpose | +|---|---| +| `file-share/smb-password` | Samba user password | +| `file-share/filebrowser-password` | FileBrowser admin password | + +Create these secrets before deploying the stack: + +```bash +aws secretsmanager create-secret --name file-share/smb-password --secret-string '' +aws secretsmanager create-secret --name file-share/filebrowser-password --secret-string '' +``` + +## Deploy + +```bash +npm install +npx cdk deploy +``` + +The stack outputs the instance's private IP for SMB and FileBrowser access. + +## Expanding Storage + +The 500 GiB data volume can be expanded without downtime: + +1. Modify the volume size in `lib/file-share-stack.ts` +2. Deploy: `npx cdk deploy` +3. SSH into the instance via SSM and resize the filesystem: + ```bash + sudo growpart /dev/xvdf 1 # if partitioned + sudo resize2fs /dev/xvdf + ``` diff --git a/bin/app.ts b/bin/app.ts new file mode 100644 index 0000000..31254cf --- /dev/null +++ b/bin/app.ts @@ -0,0 +1,11 @@ +#!/usr/bin/env node +import "source-map-support/register"; +import * as cdk from "aws-cdk-lib"; +import { FileShareStack } from "../lib/file-share-stack"; + +const app = new cdk.App(); + +new FileShareStack(app, "file-share", { + stackName: "file-share", + env: { account: "328440206208", region: "us-east-1" }, +}); diff --git a/cdk.context.json b/cdk.context.json new file mode 100644 index 0000000..068ec0c --- /dev/null +++ b/cdk.context.json @@ -0,0 +1,47 @@ +{ + "vpc-provider:account=328440206208:filter.vpc-id=vpc-0d3d4b67bd0cf8a68:region=us-east-1:returnAsymmetricSubnets=true": { + "vpcId": "vpc-0d3d4b67bd0cf8a68", + "vpcCidrBlock": "10.20.0.0/16", + "ownerAccountId": "328440206208", + "availabilityZones": [], + "vpnGatewayId": "vgw-073737d44762dffc2", + "subnetGroups": [ + { + "name": "Private", + "type": "Private", + "subnets": [ + { + "subnetId": "subnet-04e38c507e96f1926", + "cidr": "10.20.30.0/24", + "availabilityZone": "us-east-1a", + "routeTableId": "rtb-06a2f56f492b9b4de" + }, + { + "subnetId": "subnet-0a0b4fc6f296dfba5", + "cidr": "10.20.40.0/24", + "availabilityZone": "us-east-1b", + "routeTableId": "rtb-01e152fe5cabca7d6" + } + ] + }, + { + "name": "Public", + "type": "Public", + "subnets": [ + { + "subnetId": "subnet-0eea820effe1b3ae5", + "cidr": "10.20.10.0/24", + "availabilityZone": "us-east-1a", + "routeTableId": "rtb-0f2232493a5c43fe8" + }, + { + "subnetId": "subnet-0012f5895182c1580", + "cidr": "10.20.20.0/24", + "availabilityZone": "us-east-1b", + "routeTableId": "rtb-0f2232493a5c43fe8" + } + ] + } + ] + } +} diff --git a/cdk.json b/cdk.json new file mode 100644 index 0000000..4070f75 --- /dev/null +++ b/cdk.json @@ -0,0 +1,21 @@ +{ + "app": "npx ts-node bin/app.ts", + "watch": { + "include": ["**"], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "node_modules", + "cdk.out" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": ["aws"] + } +} diff --git a/lib/file-share-stack.ts b/lib/file-share-stack.ts new file mode 100644 index 0000000..56165a9 --- /dev/null +++ b/lib/file-share-stack.ts @@ -0,0 +1,212 @@ +import * as cdk from "aws-cdk-lib"; +import * as ec2 from "aws-cdk-lib/aws-ec2"; +import * as iam from "aws-cdk-lib/aws-iam"; +import * as dlm from "aws-cdk-lib/aws-dlm"; +import { Construct } from "constructs"; + +export class FileShareStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const vpc = ec2.Vpc.fromLookup(this, "SeaHavenVpc", { + vpcId: "vpc-0d3d4b67bd0cf8a68", + }); + + const privateSubnet1 = ec2.Subnet.fromSubnetAttributes( + this, "PrivateSubnet1", { + subnetId: "subnet-04e38c507e96f1926", + availabilityZone: "us-east-1a", + } + ); + + const sg = new ec2.SecurityGroup(this, "SecurityGroup", { + vpc, + securityGroupName: "file-share", + description: "File share - SMB and FileBrowser via VPN", + allowAllOutbound: true, + }); + + sg.addIngressRule(ec2.Peer.ipv4("10.10.0.0/16"), ec2.Port.tcp(445), "SMB from office VPN"); + sg.addIngressRule(ec2.Peer.ipv4("10.20.0.0/16"), ec2.Port.tcp(445), "SMB from VPC"); + sg.addIngressRule(ec2.Peer.ipv4("10.10.0.0/16"), ec2.Port.tcp(8080), "FileBrowser from office VPN"); + sg.addIngressRule(ec2.Peer.ipv4("10.20.0.0/16"), ec2.Port.tcp(8080), "FileBrowser from VPC"); + + const role = new iam.Role(this, "InstanceRole", { + roleName: "file-share-instance", + assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"), + managedPolicies: [ + iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"), + ], + }); + + role.addToPolicy(new iam.PolicyStatement({ + actions: ["secretsmanager:GetSecretValue"], + resources: [ + `arn:aws:secretsmanager:us-east-1:328440206208:secret:file-share/*`, + ], + })); + + const userData = ec2.UserData.forLinux(); + userData.addCommands( + "set -euxo pipefail", + "", + "# ── Data volume ──", + "DATA_DEVICE=/dev/$(lsblk -dno NAME | grep -v $(lsblk -no PKNAME $(findmnt -n -o SOURCE /) 2>/dev/null || echo xvda) | head -1)", + "if ! blkid \"$DATA_DEVICE\"; then", + " mkfs.ext4 -L file-share-data \"$DATA_DEVICE\"", + "fi", + "mkdir -p /data", + "echo \"LABEL=file-share-data /data ext4 defaults,nofail 0 2\" >> /etc/fstab", + "mount -a", + "mkdir -p /data/share", + "", + "# ── Samba ──", + "dnf install -y samba samba-common jq", + "", + "useradd --system --no-create-home --shell /sbin/nologin adam || true", + "chown adam:adam /data/share", + "", + "SMB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id file-share/smb-password --query SecretString --output text --region us-east-1)", + "(echo \"$SMB_PASSWORD\"; echo \"$SMB_PASSWORD\") | smbpasswd -s -a adam", + "", + "cat > /etc/samba/smb.conf << 'SMBEOF'", + "[global]", + "workgroup = SEAHAVEN", + "server string = Sea Haven File Share", + "security = user", + "map to guest = never", + "log file = /var/log/samba/log.%m", + "max log size = 1000", + "server min protocol = SMB3", + "", + "# macOS Finder optimizations", + "vfs objects = catia fruit streams_xattr", + "fruit:metadata = stream", + "fruit:model = MacSamba", + "fruit:posix_rename = yes", + "fruit:veto_appledouble = no", + "fruit:nfs_aces = no", + "fruit:wipe_intentionally_left_blank_rfork = yes", + "fruit:delete_empty_adfiles = yes", + "", + "[files]", + "path = /data/share", + "browseable = yes", + "writable = yes", + "valid users = adam", + "create mask = 0644", + "directory mask = 0755", + "SMBEOF", + "", + "systemctl enable --now smb nmb", + "", + "# ── FileBrowser ──", + 'FB_VERSION=$(curl -sf "https://api.github.com/repos/filebrowser/filebrowser/releases/latest" | jq -r .tag_name)', + 'FB_URL="https://github.com/filebrowser/filebrowser/releases/download/${FB_VERSION}/linux-arm64-filebrowser.tar.gz"', + "curl -sfL \"$FB_URL\" | tar xz -C /usr/local/bin filebrowser", + "chmod +x /usr/local/bin/filebrowser", + "", + "mkdir -p /etc/filebrowser", + "FB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id file-share/filebrowser-password --query SecretString --output text --region us-east-1)", + "FB_HASH=$(filebrowser hash \"$FB_PASSWORD\")", + "", + "cat > /etc/filebrowser/config.json << FBEOF", + "{", + " \"address\": \"0.0.0.0\",", + " \"port\": 8080,", + " \"root\": \"/data/share\",", + " \"database\": \"/etc/filebrowser/filebrowser.db\",", + " \"log\": \"/var/log/filebrowser.log\"", + "}", + "FBEOF", + "", + "filebrowser config init --config /etc/filebrowser/config.json", + "filebrowser users add admin \"$FB_PASSWORD\" --config /etc/filebrowser/config.json --perm.admin", + "", + "cat > /etc/systemd/system/filebrowser.service << 'SVCEOF'", + "[Unit]", + "Description=FileBrowser", + "After=network.target", + "", + "[Service]", + "Type=simple", + "ExecStart=/usr/local/bin/filebrowser --config /etc/filebrowser/config.json", + "Restart=always", + "RestartSec=5", + "", + "[Install]", + "WantedBy=multi-user.target", + "SVCEOF", + "", + "systemctl daemon-reload", + "systemctl enable --now filebrowser", + ); + + const instance = new ec2.Instance(this, "Instance", { + instanceName: "file-share", + vpc, + vpcSubnets: { subnets: [privateSubnet1] }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.SMALL), + machineImage: ec2.MachineImage.latestAmazonLinux2023({ + cpuType: ec2.AmazonLinuxCpuType.ARM_64, + }), + securityGroup: sg, + role, + userData, + blockDevices: [ + { + deviceName: "/dev/xvda", + volume: ec2.BlockDeviceVolume.ebs(20, { + volumeType: ec2.EbsDeviceVolumeType.GP3, + encrypted: true, + }), + }, + { + deviceName: "/dev/xvdf", + volume: ec2.BlockDeviceVolume.ebs(500, { + volumeType: ec2.EbsDeviceVolumeType.GP3, + encrypted: true, + }), + }, + ], + }); + + cdk.Tags.of(instance).add("file-share-backup", "true"); + + const dlmRole = new iam.Role(this, "DlmRole", { + roleName: "file-share-dlm", + assumedBy: new iam.ServicePrincipal("dlm.amazonaws.com"), + managedPolicies: [ + iam.ManagedPolicy.fromAwsManagedPolicyName( + "service-role/AWSDataLifecycleManagerServiceRole" + ), + ], + }); + + new dlm.CfnLifecyclePolicy(this, "SnapshotPolicy", { + description: "Nightly EBS snapshots for file share data volume", + state: "ENABLED", + executionRoleArn: dlmRole.roleArn, + policyDetails: { + resourceTypes: ["INSTANCE"], + targetTags: [{ key: "file-share-backup", value: "true" }], + schedules: [{ + name: "file-share-nightly", + createRule: { interval: 24, intervalUnit: "HOURS", times: ["06:00"] }, + retainRule: { count: 30 }, + copyTags: true, + tagsToAdd: [{ key: "file-share-backup", value: "true" }], + }], + }, + }); + + new cdk.CfnOutput(this, "InstanceId", { + value: instance.instanceId, + }); + + new cdk.CfnOutput(this, "PrivateIp", { + value: instance.instancePrivateIp, + description: "Use for SMB (smb:///files) and FileBrowser (http://:8080)", + }); + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e509004 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,521 @@ +{ + "name": "file-share", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "file-share", + "version": "1.0.0", + "dependencies": { + "aws-cdk-lib": "^2.252.0", + "constructs": "^10.0.0" + }, + "bin": { + "app": "bin/app.js" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "aws-cdk": "^2.252.0", + "source-map-support": "^0.5.21", + "typescript": "~5.7.0" + } + }, + "node_modules/@aws-cdk/asset-awscli-v1": { + "version": "2.2.273", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.273.tgz", + "integrity": "sha512-X57HYUtHt9BQrlrzUNcMyRsDUCoakYNnY6qh5lNwRCHPtQoTfXmuISkfLk0AjLkcbS5lw1LLTQFiQhTDXfiTvg==", + "license": "Apache-2.0" + }, + "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.1.tgz", + "integrity": "sha512-We4bmHaowOPHr+IQR4/FyTGjRfjgBj4ICMjtqmJeBDWad3Q/6St12NT07leNtyuukv2qMhtSZJQorD8KpKTwRA==", + "license": "Apache-2.0" + }, + "node_modules/@aws-cdk/cloud-assembly-schema": { + "version": "53.24.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-53.24.0.tgz", + "integrity": "sha512-rCwsd0Y9z4CUmV5FhzjbO2MprXjKG0rxCACuLEY40lD+wInvgcHer0lSDo7Xq9Sxe/IoNe/Wxb2YP3GgxvT3GA==", + "bundleDependencies": [ + "jsonschema", + "semver" + ], + "license": "Apache-2.0", + "dependencies": { + "jsonschema": "~1.4.1", + "semver": "^7.8.0" + }, + "engines": { + "node": ">= 18.0.0" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { + "version": "1.4.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { + "version": "7.8.0", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/node": { + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/aws-cdk": { + "version": "2.1122.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1122.0.tgz", + "integrity": "sha512-AI2Ks9qioWLvBPD4IoEtTet3wUG/o/q6U3WR3VCQKH5sNYLLPALo8o9sermNpMnfd1OQkqhL20tp4cEyojrIZg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "cdk": "bin/cdk" + }, + "engines": { + "node": ">= 18.0.0" + } + }, + "node_modules/aws-cdk-lib": { + "version": "2.254.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.254.0.tgz", + "integrity": "sha512-O7fn6fu1FXb0BgoO/+WeiBXZ16H/q6z4fOndjdG62c9bPU7Z/UeW5gz7qBiwLm4ERvTObobLCqv7wjd8bp+v3A==", + "bundleDependencies": [ + "@balena/dockerignore", + "@aws-cdk/cloud-assembly-api", + "case", + "fs-extra", + "ignore", + "jsonschema", + "minimatch", + "punycode", + "semver", + "table", + "yaml", + "mime-types" + ], + "license": "Apache-2.0", + "dependencies": { + "@aws-cdk/asset-awscli-v1": "2.2.273", + "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.1", + "@aws-cdk/cloud-assembly-api": "^2.2.3", + "@aws-cdk/cloud-assembly-schema": "^53.21.0", + "@balena/dockerignore": "^1.0.2", + "case": "1.6.3", + "fs-extra": "^11.3.3", + "ignore": "^5.3.2", + "jsonschema": "^1.5.0", + "mime-types": "^2.1.35", + "minimatch": "^10.2.3", + "punycode": "^2.3.1", + "semver": "^7.7.4", + "table": "^6.9.0", + "yaml": "1.10.3" + }, + "engines": { + "node": ">= 20.0.0" + }, + "peerDependencies": { + "constructs": "^10.5.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/@aws-cdk/cloud-assembly-api": { + "version": "2.2.3", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "jsonschema": "~1.4.1", + "semver": "^7.7.4" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "@aws-cdk/cloud-assembly-schema": ">=53.21.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { + "version": "1.0.2", + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/aws-cdk-lib/node_modules/ajv": { + "version": "8.18.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/aws-cdk-lib/node_modules/ansi-regex": { + "version": "5.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/ansi-styles": { + "version": "4.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aws-cdk-lib/node_modules/astral-regex": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/balanced-match": { + "version": "4.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/aws-cdk-lib/node_modules/brace-expansion": { + "version": "5.0.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/aws-cdk-lib/node_modules/case": { + "version": "1.6.3", + "inBundle": true, + "license": "(MIT OR GPL-3.0-or-later)", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/color-convert": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/color-name": { + "version": "1.1.4", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/emoji-regex": { + "version": "8.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/fast-deep-equal": { + "version": "3.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/fast-uri": { + "version": "3.1.2", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/aws-cdk-lib/node_modules/fs-extra": { + "version": "11.3.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/aws-cdk-lib/node_modules/graceful-fs": { + "version": "4.2.11", + "inBundle": true, + "license": "ISC" + }, + "node_modules/aws-cdk-lib/node_modules/ignore": { + "version": "5.3.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/aws-cdk-lib/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/json-schema-traverse": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/jsonfile": { + "version": "6.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/jsonschema": { + "version": "1.5.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/aws-cdk-lib/node_modules/lodash.truncate": { + "version": "4.4.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/aws-cdk-lib/node_modules/mime-db": { + "version": "1.52.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/mime-types": { + "version": "2.1.35", + "inBundle": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/minimatch": { + "version": "10.2.5", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/aws-cdk-lib/node_modules/punycode": { + "version": "2.3.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/aws-cdk-lib/node_modules/require-from-string": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/semver": { + "version": "7.7.4", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aws-cdk-lib/node_modules/slice-ansi": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/aws-cdk-lib/node_modules/string-width": { + "version": "4.2.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/strip-ansi": { + "version": "6.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aws-cdk-lib/node_modules/table": { + "version": "6.9.0", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/universalify": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-cdk-lib/node_modules/yaml": { + "version": "1.10.3", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/constructs": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.6.0.tgz", + "integrity": "sha512-TxHOnBO5zMo/G76ykzGF/wMpEHu257TbWiIxP9K0Yv/+t70UzgBQiTqjkAsWOPC6jW91DzJI0+ehQV6xDRNBuQ==", + "license": "Apache-2.0" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f8412cb --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "file-share", + "version": "1.0.0", + "bin": { + "app": "bin/app.js" + }, + "scripts": { + "build": "tsc", + "cdk": "cdk", + "synth": "cdk synth", + "deploy": "cdk deploy", + "diff": "cdk diff" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "aws-cdk": "^2.252.0", + "source-map-support": "^0.5.21", + "typescript": "~5.7.0" + }, + "dependencies": { + "aws-cdk-lib": "^2.252.0", + "constructs": "^10.0.0" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2b2e2de --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "lib": ["ES2022"], + "types": ["node"], + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "inlineSourceMap": true, + "inlineSources": true, + "strictPropertyInitialization": false, + "outDir": "./cdk.out", + "rootDir": ".", + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "esModuleInterop": true + }, + "exclude": ["node_modules", "cdk.out"] +}