File size: 3,224 Bytes
7aec436
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const SAFE_PROTOCOLS = [
  // The only protocol that's critical to block is javascript:
  // file: is indeed unsafe in places like Electron, but it's the Electron environment's job to protect against that
  // Navigating between file: is safe on the web
  'http:',
  'https:',
  'data:',
  'file:',
  'mailto:',
];

const isSafeURL = (url) => {
  try {
    const u = new URL(url, location.href);
    return SAFE_PROTOCOLS.includes(u.protocol);
  } catch (e) {
    return false;
  }
};

const shouldAlwaysOpenInNewTab = (url) => {
  try {
    const u = new URL(url, location.href);
    // Browsers don't allow opening new tabs with data: URIs
    return u.protocol === 'data:';
  } catch (e) {
    return false;
  }
};

const shouldAlwaysOpenInCurrentTab = (url) => {
  try {
    const u = new URL(url, location.href);
    // If you open a mailto: in a new tab, the browser will convert it to about:blank and just leave an empty tab
    return u.protocol === 'mailto:';
  } catch (e) {
    return false;
  }
};

const openInNewTab = (url) => {
  window.open(url);
};

const openInCurrentTab = (url) => {
  location.href = url;
};

class SpecialCloudBehaviorsProvider {
  enable () {
    this.manager.setVariable(this, '☁ url', location.href);

    document.addEventListener('paste', (e) => {
      const text = (e.clipboardData || window.clipboardData).getData('text');
      this.manager.setVariable(this, '☁ pasted', text);
    });

    this.webSocketProvider = this.manager.providers.find(i => typeof i.setProjectId === 'function');
    this.initialProjectId = this.webSocketProvider ? this.webSocketProvider.projectId : null;
  }

  handleUpdateVariable (name, value) {
    if (name === '☁ redirect') {
      if (isSafeURL(value)) {
        if (shouldAlwaysOpenInNewTab(value)) {
          openInNewTab(value);
        } else {
          openInCurrentTab(value);
        }
      }
    } else if (name === '☁ open link') {
      if (isSafeURL(value)) {
        if (shouldAlwaysOpenInCurrentTab(value)) {
          openInCurrentTab(value);
        } else {
          openInNewTab(value);
        }
      }
    } else if (name === '☁ username') {
      this.manager.parent.setUsername(value);
    } else if (name === '☁ set clipboard') {
      navigator.clipboard.writeText(value);
    } else if (name === '☁ room id') {
      if (this.webSocketProvider) {
        const newId = this.initialProjectId + (value ? `-${value}` : '');
        this.webSocketProvider.setProjectId(newId);
      }
    }
  }
}

export default function ({ scaffolding }) {
  const provider = new SpecialCloudBehaviorsProvider();
  scaffolding.addCloudProvider(provider);
  scaffolding.addCloudProviderOverride('☁ url', provider);
  scaffolding.addCloudProviderOverride('☁ redirect', provider);
  scaffolding.addCloudProviderOverride('☁ open link', provider);
  scaffolding.addCloudProviderOverride('☁ username', provider);
  scaffolding.addCloudProviderOverride('☁ set clipboard', provider);
  scaffolding.addCloudProviderOverride('☁ pasted', provider);
  scaffolding.addCloudProviderOverride('☁ room id', provider);
}