#!/usr/bin/env bash # br-linkedin - BlackRoad OS LinkedIn CLI # Post to BlackRoad OS, Inc. company page from terminal # Company URN: urn:li:organization:111783522 set -euo pipefail # Config LINKEDIN_ORG_URN="urn:li:organization:111783522" LINKEDIN_API_URL="https://api.linkedin.com/v2/ugcPosts" ENV_FILE="$HOME/.blackroad/.env.linkedin" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # Help show_help() { cat << EOF ${BLUE}br-linkedin${NC} - Post to BlackRoad OS, Inc. LinkedIn company page ${YELLOW}USAGE:${NC} br-linkedin post "Your post content here" br-linkedin setup br-linkedin verify br-linkedin help ${YELLOW}COMMANDS:${NC} post Post to LinkedIn company page setup Configure OAuth token verify Verify token and permissions help Show this help ${YELLOW}EXAMPLES:${NC} br-linkedin post "Shipping v1.0 today 🚀" br-linkedin post "BlackRoad OS now supports 30k+ agents" ${YELLOW}SETUP:${NC} 1. Run: br-linkedin setup 2. Follow OAuth flow 3. Save access token 4. Start posting ${YELLOW}ORGANIZATION:${NC} BlackRoad OS, Inc. URN: ${LINKEDIN_ORG_URN} EOF } # Setup OAuth setup_oauth() { echo -e "${BLUE}br-linkedin setup${NC}" echo "" echo "To post to LinkedIn, you need an OAuth access token." echo "" echo -e "${YELLOW}Step 1: Create LinkedIn Developer App${NC}" echo " → https://www.linkedin.com/developers/apps" echo " → Name: BlackRoad OS CLI" echo " → Page: BlackRoad OS, Inc." echo "" echo -e "${YELLOW}Step 2: Enable Required Products${NC}" echo " → Share on LinkedIn" echo " → Sign In with LinkedIn" echo "" echo -e "${YELLOW}Step 3: Note Your Credentials${NC}" read -p " Client ID: " CLIENT_ID read -sp " Client Secret: " CLIENT_SECRET echo "" echo "" echo -e "${YELLOW}Step 4: Authorize App${NC}" AUTH_URL="https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=${CLIENT_ID}&redirect_uri=http://localhost:8080&scope=w_organization_social%20r_organization_social" echo " Opening browser to authorize..." echo " URL: ${AUTH_URL}" if command -v open &> /dev/null; then open "$AUTH_URL" elif command -v xdg-open &> /dev/null; then xdg-open "$AUTH_URL" else echo " Please open this URL manually: ${AUTH_URL}" fi echo "" read -p " After authorizing, paste the 'code' from URL: " AUTH_CODE echo "" echo -e "${YELLOW}Step 5: Exchange Code for Token${NC}" TOKEN_RESPONSE=$(curl -s -X POST https://www.linkedin.com/oauth/v2/accessToken \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=${AUTH_CODE}" \ -d "redirect_uri=http://localhost:8080" \ -d "client_id=${CLIENT_ID}" \ -d "client_secret=${CLIENT_SECRET}") ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"access_token":"[^"]*"' | cut -d'"' -f4) EXPIRES_IN=$(echo "$TOKEN_RESPONSE" | grep -o '"expires_in":[0-9]*' | cut -d':' -f2) if [ -z "$ACCESS_TOKEN" ]; then echo -e "${RED}✗ Failed to get access token${NC}" echo "$TOKEN_RESPONSE" exit 1 fi mkdir -p "$HOME/.blackroad" cat > "$ENV_FILE" << EOL # LinkedIn OAuth Configuration # Generated: $(date) LINKEDIN_ACCESS_TOKEN=${ACCESS_TOKEN} LINKEDIN_EXPIRES_IN=${EXPIRES_IN} LINKEDIN_CLIENT_ID=${CLIENT_ID} LINKEDIN_CLIENT_SECRET=${CLIENT_SECRET} EOL chmod 600 "$ENV_FILE" echo -e "${GREEN}✓ Setup complete!${NC}" echo "" echo "Token saved to: $ENV_FILE" echo "Expires in: $((EXPIRES_IN / 86400)) days" echo "" echo "Test it:" echo " br-linkedin verify" echo " br-linkedin post \"Hello from the terminal!\"" } # Verify token verify_token() { if [ ! -f "$ENV_FILE" ]; then echo -e "${RED}✗ Not configured${NC}" echo "Run: br-linkedin setup" exit 1 fi source "$ENV_FILE" if [ -z "${LINKEDIN_ACCESS_TOKEN:-}" ]; then echo -e "${RED}✗ No access token found${NC}" echo "Run: br-linkedin setup" exit 1 fi echo -e "${BLUE}Verifying token...${NC}" RESPONSE=$(curl -s -H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \ "https://api.linkedin.com/v2/organizationalEntityAcls?q=roleAssignee") if echo "$RESPONSE" | grep -q "111783522"; then echo -e "${GREEN}✓ Token valid${NC}" echo -e "${GREEN}✓ Access to BlackRoad OS, Inc. confirmed${NC}" return 0 else echo -e "${RED}✗ Token invalid or missing permissions${NC}" echo "$RESPONSE" exit 1 fi } # Post to LinkedIn post_to_linkedin() { local TEXT="$1" if [ -z "$TEXT" ]; then echo -e "${RED}✗ Post text required${NC}" echo "Usage: br-linkedin post \"Your text here\"" exit 1 fi if [ ! -f "$ENV_FILE" ]; then echo -e "${RED}✗ Not configured${NC}" echo "Run: br-linkedin setup" exit 1 fi source "$ENV_FILE" if [ -z "${LINKEDIN_ACCESS_TOKEN:-}" ]; then echo -e "${RED}✗ No access token${NC}" echo "Run: br-linkedin setup" exit 1 fi echo -e "${BLUE}Posting to LinkedIn...${NC}" echo "" echo -e "${YELLOW}Preview:${NC}" echo "─────────────────────────────────────" echo "$TEXT" echo "─────────────────────────────────────" echo "" # Build JSON payload PAYLOAD=$(jq -n \ --arg text "$TEXT" \ --arg org "$LINKEDIN_ORG_URN" \ '{ author: $org, lifecycleState: "PUBLISHED", specificContent: { "com.linkedin.ugc.ShareContent": { shareCommentary: { text: $text }, shareMediaCategory: "NONE" } }, visibility: { "com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC" } }') RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$LINKEDIN_API_URL" \ -H "Authorization: Bearer $LINKEDIN_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d "$PAYLOAD") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | head -n-1) if [ "$HTTP_CODE" = "201" ]; then POST_ID=$(echo "$BODY" | grep -o '"id":"[^"]*"' | cut -d'"' -f4) echo -e "${GREEN}✓ Posted successfully!${NC}" echo "" echo "Post ID: $POST_ID" echo "View at: https://www.linkedin.com/company/blackroad-os-inc/" else echo -e "${RED}✗ Post failed (HTTP $HTTP_CODE)${NC}" echo "$BODY" exit 1 fi } # Main case "${1:-}" in post) shift post_to_linkedin "$*" ;; setup) setup_oauth ;; verify) verify_token ;; help|--help|-h) show_help ;; *) echo -e "${RED}Unknown command: ${1:-}${NC}" echo "" show_help exit 1 ;; esac