Browse Source

ref: Consolidate QR codes (#24121)

Here(#23981) we introduced a new frontend package for QR codes.

In this PR I removed the old QR code component that worked with matrix data.
I refactored the backend because there's no need to send matrix data anymore - the new package is able to generate QR codes from strings.
Matej Minar 4 years ago
parent
commit
e96506e3b3

+ 0 - 44
docs-ui/components/qrcode.stories.js

@@ -1,44 +0,0 @@
-import React from 'react';
-
-import Qrcode from 'app/components/qrcode';
-
-export default {
-  title: 'UI/Qrcode',
-};
-
-export const Default = () => (
-  <Qrcode
-    code={[
-      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0],
-      [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
-      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-    ]}
-  />
-);
-
-Default.storyName = 'default';

+ 0 - 1
requirements-base.txt

@@ -37,7 +37,6 @@ python-memcached==1.59
 python-u2flib-server==5.0.0
 python-u2flib-server==5.0.0
 python3-saml==1.4.1
 python3-saml==1.4.1
 PyYAML==5.3
 PyYAML==5.3
-qrcode==6.1
 rb==1.8
 rb==1.8
 redis-py-cluster==2.1.0
 redis-py-cluster==2.1.0
 redis==3.3.11
 redis==3.3.11

+ 1 - 1
src/sentry/api/endpoints/user_authenticator_enroll.py

@@ -126,7 +126,7 @@ class UserAuthenticatorEnrollEndpoint(UserEndpoint):
             pass
             pass
 
 
         if interface_id == "totp":
         if interface_id == "totp":
-            response["qrcode"] = interface.get_provision_qrcode(user.email)
+            response["qrcode"] = interface.get_provision_url(user.email)
 
 
         if interface_id == "u2f":
         if interface_id == "u2f":
             response["challenge"] = interface.start_enrollment()
             response["challenge"] = interface.start_enrollment()

+ 2 - 2
src/sentry/auth/authenticators/totp.py

@@ -16,5 +16,5 @@ class TotpInterface(OtpMixin, AuthenticatorInterface):
         "generated every 30 seconds."
         "generated every 30 seconds."
     )
     )
 
 
-    def get_provision_qrcode(self, user, issuer=None):
-        return self.make_otp().get_provision_qrcode(user, issuer=issuer)
+    def get_provision_url(self, user, issuer=None):
+        return self.make_otp().get_provision_url(user, issuer=issuer)

+ 0 - 40
src/sentry/static/sentry/app/components/qrcode.tsx

@@ -1,40 +0,0 @@
-import React from 'react';
-import styled from '@emotion/styled';
-
-import {Authenticator} from 'app/types';
-
-type Props = {
-  code: NonNullable<(Authenticator & {id: 'totp'})['qrcode']>;
-};
-
-const Qrcode = ({code}: Props) => (
-  <Table>
-    <tbody>
-      {code.map((row, i) => (
-        <tr key={i}>
-          {row.map((cell, j) => (cell ? <BlackCell key={j} /> : <WhiteCell key={j} />))}
-        </tr>
-      ))}
-    </tbody>
-  </Table>
-);
-
-const Cell = styled('td')`
-  height: 6px;
-  width: 6px;
-  padding: 0;
-`;
-
-const BlackCell = styled(Cell)`
-  background-color: black;
-`;
-
-const WhiteCell = styled(Cell)`
-  background-color: white;
-`;
-
-const Table = styled('table')`
-  margin: 0;
-`;
-
-export default Qrcode;

+ 1 - 3
src/sentry/static/sentry/app/types/index.tsx

@@ -570,8 +570,6 @@ export type AuthenticatorDevice = {
   timestamp?: string;
   timestamp?: string;
 };
 };
 
 
-type QRCode = (0 | 1)[][];
-
 export type Authenticator = {
 export type Authenticator = {
   /**
   /**
    * String used to display on button for user as CTA to enroll
    * String used to display on button for user as CTA to enroll
@@ -623,7 +621,7 @@ export type Authenticator = {
       }
       }
     | {
     | {
         id: 'totp';
         id: 'totp';
-        qrcode: QRCode;
+        qrcode: string;
       }
       }
     | {
     | {
         id: 'u2f';
         id: 'u2f';

+ 2 - 2
src/sentry/static/sentry/app/views/settings/account/accountSecurity/accountSecurityEnroll.tsx

@@ -1,5 +1,6 @@
 import React from 'react';
 import React from 'react';
 import {RouteComponentProps, withRouter} from 'react-router';
 import {RouteComponentProps, withRouter} from 'react-router';
+import QRCode from 'qrcode.react';
 
 
 import {
 import {
   addErrorMessage,
   addErrorMessage,
@@ -11,7 +12,6 @@ import {fetchOrganizationByMember} from 'app/actionCreators/organizations';
 import Button from 'app/components/button';
 import Button from 'app/components/button';
 import CircleIndicator from 'app/components/circleIndicator';
 import CircleIndicator from 'app/components/circleIndicator';
 import {PanelItem} from 'app/components/panels';
 import {PanelItem} from 'app/components/panels';
-import Qrcode from 'app/components/qrcode';
 import U2fsign from 'app/components/u2f/u2fsign';
 import U2fsign from 'app/components/u2f/u2fsign';
 import {t} from 'app/locale';
 import {t} from 'app/locale';
 import {Authenticator} from 'app/types';
 import {Authenticator} from 'app/types';
@@ -67,7 +67,7 @@ const getFields = ({
     return [
     return [
       () => (
       () => (
         <PanelItem key="qrcode" justifyContent="center" p={2}>
         <PanelItem key="qrcode" justifyContent="center" p={2}>
-          <Qrcode code={authenticator.qrcode} />
+          <QRCode value={authenticator.qrcode} size={228} />
         </PanelItem>
         </PanelItem>
       ),
       ),
       () => (
       () => (

+ 0 - 8
src/sentry/utils/otp.py

@@ -1,7 +1,6 @@
 import time
 import time
 import hmac
 import hmac
 import base64
 import base64
-import qrcode
 import hashlib
 import hashlib
 
 
 from datetime import datetime
 from datetime import datetime
@@ -95,10 +94,3 @@ class TOTP:
         if self.interval != 30:
         if self.interval != 30:
             rv += "&period=%d" % self.interval
             rv += "&period=%d" % self.interval
         return rv
         return rv
-
-    def get_provision_qrcode(self, user, issuer=None):
-        qr = qrcode.QRCode(border=0)
-        qr.add_data(self.get_provision_url(user, issuer=issuer))
-
-        # Frontend expects the matrix to be serialized as 1/0, not True/False
-        return [[int(c) for c in row] for row in qr.get_matrix()]

File diff suppressed because it is too large
+ 0 - 0
tests/fixtures/totp_qrcode.json


+ 0 - 12
tests/js/spec/components/qrcode.spec.jsx

@@ -1,12 +0,0 @@
-import React from 'react';
-
-import {mountWithTheme} from 'sentry-test/enzyme';
-
-import Qrcode from 'app/components/qrcode';
-
-describe('Qrcode', function () {
-  it('renders', function () {
-    const wrapper = mountWithTheme(<Qrcode code={[[0, 1, 1, 0, 0, 0, 0, 0]]} />);
-    expect(wrapper).toSnapshot();
-  });
-});

Some files were not shown because too many files changed in this diff